How To

REST API 설계 원칙 - 면접에도 나오는 좋은 API의 조건

REST API 설계는 실무 감각이자 면접 단골 소재예요. URI 네이밍 규칙, HTTP 메서드별 멱등성과 안전성, 상태 코드, 버전 관리, HATEOAS까지 주니어 개발자가 알아야 할 원칙을 한 번에 정리했어요.
2026.07.14
REST API 설계 원칙 - 면접에도 나오는 좋은 API의 조건

"이 API, RESTful한가요?" 면접에서 이런 질문을 받으면 자신 있게 답할 수 있으신가요?

CRUD API는 만들어봤는데 막상 "왜 이렇게 설계했나요?"라고 물어보면 말문이 막히는 경우, 많으실 거예요. URI에 동사를 넣거나, 모든 요청을 POST로 처리하거나, 성공하면 200 실패하면 500만 반환하는 API를 무의식중에 만들고 있었을 수도 있고요.

REST API 설계는 그냥 "동작하면 되는 것"이 아니라, 실무 감각을 보여주는 영역이에요. 그리고 재미있게도, 실무에서 지키는 설계 원칙이 곧 면접에서 자주 나오는 개념이기도 해요. 이 글에서는 URI 네이밍부터 HTTP 메서드의 멱등성, 상태 코드, 버전 관리, 그리고 면접 단골 소재인 HATEOAS까지 한 번에 정리해 볼게요.


REST가 뭔가요? — 핵심 제약조건 먼저 정리하기

REST(Representational State Transfer)는 웹의 특성을 활용해 시스템을 설계하는 아키텍처 스타일이에요. 실무에서 자주 언급되는 두 가지 핵심 제약조건만 먼저 짚고 갈게요.

첫째, 균일한 인터페이스(uniform interface)예요. RESTful API는 GET, POST, PUT, PATCH, DELETE 같은 표준 HTTP 메서드로 자원을 조작해요[4]. 둘째, 무상태성(stateless)이에요. HTTP 요청은 서로 독립적이고 어떤 순서로도 처리될 수 있어야 해요. 서버는 요청 사이에 임시 상태를 유지하지 않고, 상태는 오직 리소스 자체에만 저장돼요[4]. 이 덕분에 서버를 수평으로 확장하기 쉬워지지만, 반대로 백엔드 스토리지를 어떻게 확장할지는 별도로 고민해야 해요[4].

이 두 가지만 기억해도 "이 API가 RESTful한 이유"를 설명할 수 있는 기초가 생겨요. 그럼 이제 실제로 어떻게 설계해야 하는지 하나씩 살펴볼게요.


URI는 명사로, 동사는 HTTP 메서드로

가장 흔한 실수가 바로 여기서 나와요. URI에 동작을 넣는 거예요.

나쁜 예시:

POST /create-order
GET  /getOrderById?id=5
POST /orders/5/delete

좋은 예시:

POST   /orders          → 주문 생성
GET    /orders/5        → 주문 5번 조회
DELETE /orders/5        → 주문 5번 삭제

핵심은 이거예요. URI는 자원(명사)을 나타내고, 행위(동사)는 HTTP 메서드가 담당한다. /orders 대신 /create-order를 쓰면 안 되는 이유는, HTTP GET/POST/PUT/PATCH/DELETE 메서드 자체가 이미 동작의 의미를 담고 있기 때문이에요[4]. 컬렉션은 복수 명사로 표현해요. /customers는 고객 컬렉션 전체를, /customers/5는 ID가 5인 특정 고객을 가리키는 식으로 계층을 구성해요[4].

계층을 만들 때도 주의할 점이 있어요. /customers/1/orders/99/products처럼 너무 깊게 중첩하면 유지보수가 어려워져요. 가능하면 collection/item/collection 수준을 넘지 않는 게 좋아요[4]. 그리고 POST로 새 자원을 만들 때는 클라이언트가 URI를 직접 정하지 않고, 서버가 새로 생성된 자원의 URI를 할당해주는 게 원칙이에요[4].


HTTP 메서드, 멱등성과 안전성까지 알아야 진짜 아는 것

면접에서 정말 자주 나오는 질문이 "PUT과 PATCH의 차이가 뭔가요?", "멱등성이 뭔가요?" 같은 것들이에요. 표로 한 번에 정리해 볼게요.

메서드

용도

멱등성 (Idempotent)

안전성 (Safe)

GET

리소스 조회

O

O

POST

리소스 생성 (부수효과 발생 가능)

X

X

PUT

리소스 전체 교체

O

X

PATCH

리소스 부분 수정

X

X

DELETE

리소스 삭제

O

X

여기서 두 개념을 구분하는 게 중요해요.

  • 안전성(Safe): 호출해도 서버 상태를 바꾸지 않는 것. 읽기 전용 동작이에요. GET이 대표적이에요[1].

  • 멱등성(Idempotent): 같은 요청을 여러 번 보내도 결과가 항상 동일한 것. GET, PUT, DELETE는 멱등해요. 예를 들어 PUT 요청을 두 번 연속 보내도 서버의 최종 상태는 한 번 보낸 것과 같아야 해요[4]. 반면 POST는 같은 요청을 두 번 보내면 리소스가 두 개 생길 수 있어서 멱등하지 않고, PATCH도 멱등성이 보장되지 않아요[1].

실무에서 이걸 왜 알아야 할까요? 네트워크 오류로 요청이 실패했는지 확실하지 않을 때, 멱등한 메서드는 안전하게 재시도할 수 있어요. 하지만 POST를 재시도하면 중복 생성 같은 부작용이 생길 수 있죠. PUT과 PATCH도 헷갈리기 쉬운데, PUT은 리소스 전체를 교체하는 반면 PATCH는 변경된 부분만 보내기 때문에 더 효율적일 수 있어요[4].


상태 코드, 200/500만 쓰고 있다면 다시 보세요

상태 코드도 면접 단골 소재예요. 성공은 200, 실패는 500만 쓰고 있다면 클라이언트가 무엇이 잘못됐는지 알 방법이 없어요. 카테고리별로 정리해 볼게요.

카테고리

대표 코드

의미

2xx (성공)

200 OK

요청 성공, 의미는 메서드에 따라 다름[2]

201 Created

요청 성공 + 새 리소스 생성됨 (주로 POST 응답)[2]

204 No Content

성공했지만 응답 본문이 없음[2]

4xx (클라이언트 오류)

400 Bad Request

요청 구문 자체가 잘못됨[2]

401 Unauthorized

인증이 필요함 (사실상 "미인증" 상태)[2]

403 Forbidden

신원은 확인됐지만 권한이 없음[2]

404 Not Found

요청한 리소스를 찾을 수 없음[2]

409 Conflict

현재 서버 상태와 요청이 충돌함[2]

422 Unprocessable Content

구문은 맞지만 의미상 처리할 수 없음[2]

5xx (서버 오류)

500 Internal Server Error

서버가 처리 방법을 모르는 일반 오류[2]

503 Service Unavailable

유지보수·과부하 등으로 일시적으로 처리 불가[2]

401과 403을 헷갈리는 경우가 많은데, 401은 "누구인지 모르겠다"(인증 필요), 403은 "누구인지는 알지만 권한이 없다"로 구분하면 기억하기 쉬워요[2]. 마찬가지로 400과 422도 다른데, 400은 요청 자체의 문법 오류, 422는 문법은 맞지만 비즈니스 규칙상 처리할 수 없는 경우예요[2].


버전 관리, 페이지네이션, 일관된 에러 응답

API는 계속 진화하니까 버전 관리가 필요해요. 흔히 쓰는 방식은 URI 버전(/v2/customers/3), 쿼리 스트링 버전(?version=2), 헤더 버전 등이 있는데 각각 트레이드오프가 있어요. URI나 쿼리 스트링 방식은 직관적이지만, 응답에 하이퍼미디어 링크를 포함할 경우 링크마다 버전 정보를 넣어야 해서 다소 번거로워질 수 있어요[4].

목록을 반환하는 API라면 페이지네이션과 필터링도 필수예요. limit, offset 같은 쿼리 파라미터로 조회 범위를 지정하고 합리적인 기본값을 정해두는 방식이 일반적이에요. 예를 들면 이런 식이에요[4].

GET /orders?limit=25&offset=50
GET /orders?minCost=100&status=shipped

에러 응답도 일관성이 중요해요. Google의 API 설계 표준에서는 에러 발생 시 코드(code), 사람이 이해할 수 있는 메시지(message), 추가 정보(details)를 구조화해서 반환하도록 권고해요[5]. 메시지는 기술적인 사용자도 이해할 수 있을 만큼 간결하고 실행 가능해야 하고요[5]. 이렇게 포맷을 통일해두면 클라이언트가 매 엔드포인트마다 다른 에러 처리 로직을 짤 필요 없이, 중앙화된 에러 핸들링을 구현할 수 있어요[5].


면접 단골 질문 — HATEOAS와 Richardson Maturity Model

REST 얘기가 나오면 꼭 따라붙는 개념이 HATEOAS(Hypertext As The Engine Of Application State)예요. 간단히 말하면, 응답 안에 "다음에 할 수 있는 행동"을 링크로 함께 내려주는 방식이에요. 예를 들어 주문 조회 응답에 결제 링크, 취소 링크가 함께 담겨 있으면 클라이언트는 API 문서를 뒤지지 않아도 다음 행동을 발견할 수 있어요.

이 개념을 체계적으로 설명하는 게 Richardson Maturity Model(RMM)이에요. Leonard Richardson이 제안하고 Martin Fowler가 정리한 4단계 모델이에요[3].

  1. Level 0: HTTP를 그냥 RPC 호출을 감싸는 터널로만 쓰는 단계

  2. Level 1: 단일 엔드포인트 대신 개별 자원(리소스) 단위로 나누는 단계

  3. Level 2: HTTP 메서드와 상태 코드를 표준대로 일관되게 사용하는 단계 — 이 글에서 다룬 내용 대부분이 여기에 해당해요

  4. Level 3: HATEOAS까지 적용해서, 응답 자체가 클라이언트를 다음 행동으로 안내하는 단계

여기서 면접에 나올 만한 포인트가 하나 있어요. Roy Fielding(REST 개념을 처음 정의한 사람)은 Level 3, 즉 HATEOAS까지 적용해야 "진짜 REST"라고 봤어요[3]. 하지만 Fowler는 이 모델을 "합격/불합격을 가르는 체크리스트가 아니라, 개념을 이해하는 학습 도구로 봐야 한다"고 강조해요[3]. 실제로 실무에서는 Level 0이나 1은 점점 보기 어려워지고, Level 2가 가장 흔한 수준이에요[3]. 즉 HATEOAS는 이론적으로는 이상적이지만, 실무 API 대부분은 Level 2에서 멈춰 있다는 뜻이에요. 그러니 면접에서 "우리 API는 HATEOAS를 완전히 구현하지 않았다"고 말해도 괜찮아요. 오히려 "왜 그런 선택을 했는지" 설명할 수 있으면 더 좋은 답이 돼요.


실무 체크리스트로 한 번 더 점검하기

지금까지 다룬 내용을 실제 API 설계할 때 바로 써먹을 수 있는 체크리스트로 정리해봤어요. 다음 프로젝트에서 API를 설계하거나, 기존 API를 리뷰할 때 하나씩 확인해보세요.

  • [ ] URI에 동사가 들어가 있지 않은가? (/getUser 대신 GET /users/1)

  • [ ] 컬렉션은 복수 명사로, 계층은 collection/item/collection 수준을 넘지 않는가?

  • [ ] 리소스를 수정할 때 PUT(전체 교체)과 PATCH(부분 수정)를 구분해서 쓰고 있는가?

  • [ ] 재시도해도 안전한 요청(GET/PUT/DELETE)과 그렇지 않은 요청(POST/PATCH)을 구분하고 있는가?

  • [ ] 성공/실패 상황마다 의미에 맞는 상태 코드를 반환하고 있는가? (200/500만 쓰고 있지 않은가)

  • [ ] 목록 조회 API에 페이지네이션과 필터링이 있는가?

  • [ ] 에러 응답 포맷이 모든 엔드포인트에서 일관되는가?

이 체크리스트를 다 통과한다면, 최소한 Richardson Maturity Model의 Level 2는 확실히 만족하는 API를 설계한 거예요. 그 정도면 실무에서도, 면접에서도 충분히 자신 있게 설명할 수 있어요.


마무리

정리하면, 좋은 REST API 설계는 결국 몇 가지 원칙으로 압축돼요. 자원은 명사로 표현하고, 행위는 HTTP 메서드로 표현하기. 메서드의 멱등성과 안전성을 정확히 이해하고 쓰기. 상태 코드로 상황을 정확히 전달하기. 버전 관리와 에러 응답을 일관되게 설계하기. 이 원칙들은 실무에서 좋은 API를 만드는 기준이자, 면접관이 지원자의 실전 감각을 판단하는 기준이기도 해요.

이런 개념들은 알고 있는 것과 면접에서 조리 있게 설명하는 건 또 다른 문제예요. 모의 면접 기능으로 실제 질문 상황을 연습해보면 훨씬 자신감이 붙어요. 그리고 Spring Boot 같은 백엔드 프레임워크로 REST API를 직접 구현해보면서 원칙을 몸에 익히는 것도 좋은 방법이에요. 더 깊이 있는 기술 개념이 궁금하다면 트리업의 기술 가이드도 참고해보세요.

작은 원칙 하나하나가 쌓여서 "설계를 이해하고 만드는 개발자"를 만들어요. 오늘 정리한 내용부터 차근차근 적용해보세요!


참고 자료

RESTAPI
주니어개발자
HTTP메서드
백엔드면접
개발자면접준비
API설계
Updated 2026.07.14

Recommended for you

  • SQL 윈도우 함수 실전 가이드 - 데이터 분석가 필수 쿼리
    How To
    SQL 윈도우 함수, GROUP BY로는 안 풀리는 문제를 해결하는 핵심 도구예요. ROW_NUMBER, RANK, DENSE_RANK, LAG/LEAD, 누적 합계와 이동 평균까지 실무 예제 쿼리로 정리했어요. 데이터 분석가 면접과 실무에서 바로 쓸 수 있는 SQL 문법을 확인해보세요.
  • Docker 입문 - 신입 개발자가 처음 컨테이너를 다루는 법
    How To
    채용 공고마다 "Docker 사용 경험 우대"가 보이는데 써본 적 없다면? 컨테이너와 가상머신의 차이, 이미지·Dockerfile 개념부터 build/run 명령어, 직접 따라 하는 미니 실습까지 신입 개발자 눈높이로 정리했어요. 오늘 바로 컨테이너 하나 실행해볼 수 있어요.
  • Git 브랜치 전략 완전 정복 - 신입이 꼭 알아야 할 협업 워크플로우
    How To
    Git commit, push는 익숙한데 팀 협업은 처음이신가요? Git Flow, GitHub Flow, GitLab Flow, Trunk-Based Development까지 4가지 브랜치 전략의 구조와 장단점, 실제 브랜치 이름 예시를 비교표로 정리했어요. 신입 개발자를 위한 실전 체크리스트도 확인해보세요.
  • PostgreSQL vs MySQL, 신입 개발자는 뭘 선택해야 할까요?
    Tool Comparison
    PostgreSQL과 MySQL, 실무에서는 정말 뭘 선택해야 할까요? 2025 Stack Overflow 개발자 설문 데이터와 ACID·JSON·라이선스 같은 실무 차이, 카카오뱅크·BC카드 등 국내 기업 사례까지 신입 개발자 눈높이에서 꼼꼼하게 비교해봤어요.
  • Pandas vs Polars, 데이터 분석가는 이제 뭘 써야 할까
    Tool Comparison
    Pandas와 Polars, 실제로 얼마나 다를까요? Polars 공식 벤치마크와 JetBrains 설문, 국내 채용 공고 데이터로 확인한 성능 차이와 문법 차이를 정리했어요. 주니어 데이터 분석가가 지금 당장 무엇을 우선 배워야 하는지 실무 기준으로 알려드려요.
  • Tableau vs Power BI vs Looker, 데이터 분석가라면 뭐부터 배워야 할까요?
    Tool Comparison
    Tableau, Power BI, Looker 중 무엇부터 배워야 할지 고민되는 주니어 데이터 분석가를 위한 글이에요. 가격, 학습 난이도, 글로벌 시장 평가에 더해 한국 채용 공고 실제 검색 데이터까지 꼼꼼히 비교해서 학습 우선순위를 명확하게 정리해드릴게요.