REST API 입문
REST API 입문 — 자원과 동사
HTTP 위에 API 를 짤 때 가장 자주 등장하는 단어가 REST 입니다. 뜻은 Representational State Transfer 로, Roy Fielding 의 2000 년 박사 논문에서 정리됐습니다.
1. REST 에 대한 이야기
| 사건 | 시기 |
|---|---|
| Roy Fielding "Architectural Styles" 박사 논문 | 2000 |
| RFC 7230 ~ 7235 (HTTP/1.1 재정리) | 2014 |
| OpenAPI 3.0 | 2017 |
| HATEOAS 가 다시 거론됨 | 2010s |
Fielding 이 논문에서 제시한 6 가지 제약입니다.
① Client-Server — 책임 분리
② Stateless — 각 요청은 독립
③ Cacheable — 응답이 캐시 가능 여부 명시
④ Uniform Interface — 일관된 인터페이스
⑤ Layered System — 중간 노드가 투명
⑥ Code on Demand (선택) — 거의 사용 안 됨
가장 자주 어겨지는 제약이 HATEOAS — 응답에 다음 가능한 액션 링크를 포함하는 모델. 실무 JSON API 에서는 보통 생략됩니다.
이후 의미가 느슨해져 "HTTP 동사를 쓰는 JSON API" 정도로 통용되곤 합니다.
2. 자원 중심 설계
REST 의 핵심은 "URL 은 자원 (Resource) 을 가리키고 HTTP 동사가 동작을 가리킨다" 입니다. 동사를 URL 에 넣지 않습니다.
좋은 모양:
GET /users (목록)
GET /users/123 (한 건)
POST /users (생성)
PATCH /users/123 (부분 수정)
DELETE /users/123 (삭제)
자주 보이는 안티패턴:
GET /getUsers
POST /createUser
POST /users/123/delete
자원 이름은 보통 복수형 명사. 중첩 자원은 부모-자식 관계가 명확할 때.
GET /users/123/posts (사용자 123 의 글 목록)
POST /users/123/posts (사용자 123 의 글 생성)
3. HTTP 동사와 CRUD
| 동사 | 의미 | 멱등 | 안전 |
|---|---|---|---|
| GET | 조회 | O | O |
| POST | 생성·임의 동작 | X | X |
| PUT | 전체 교체 | O | X |
| PATCH | 부분 수정 | 보통 X (구현 따라) | X |
| DELETE | 삭제 | O | X |
- 안전 (safe) — 자원 상태를 바꾸지 않음.
- 멱등 (idempotent) — 같은 요청을 여러 번 보내도 결과 같음.
PUT 과 PATCH 의 차이는 의미 — PUT 은 자원 전체를 보낸 값으로 교체, PATCH 는 일부만 수정. 실무에서는 PATCH 가 자주 쓰입니다.
4. 응답 코드
| 코드 | 용도 |
|---|---|
| 200 OK | 성공 (응답 본문 있음) |
| 201 Created | 생성 성공. Location 헤더로 새 자원 위치. |
| 204 No Content | 성공, 응답 본문 없음 (DELETE 등) |
| 400 Bad Request | 입력 오류 |
| 401 Unauthorized | 인증 안 됨 |
| 403 Forbidden | 인증됐으나 권한 없음 |
| 404 Not Found | 자원 없음 |
| 409 Conflict | 동시성·중복 |
| 422 Unprocessable Entity | 검증 실패 (의미상 오류) |
| 429 Too Many Requests | rate limit |
| 500 Internal Server Error | 서버 오류 |
| 503 Service Unavailable | 일시 장애 |
400 vs 422 의 경계는 견해차입니다. JSON 자체가 깨졌으면 400, 형식은 맞지만 의미가 안 맞으면 422 라는 흐름이 자주 보입니다.
5. 페이지네이션
Offset 기반:
GET /posts?page=3&size=20
GET /posts?offset=40&limit=20
장점은 임의 페이지 점프, UI 친화. 단점은 큰 offset 일수록 느려짐 (DB 가 OFFSET 만큼 행을 건너뛰는 비용), 동시 삽입·삭제 시 누락·중복.
Cursor 기반:
GET /posts?cursor=eyJpZCI6MTIzfQ&limit=20
응답에 nextCursor 가 포함됩니다. 클라이언트가 그걸 다음 요청에 보냅니다. 장점은 O(1) 페이징, 동시성 안정. 단점은 임의 페이지 점프 어려움.
큰 데이터·실시간 피드는 cursor 가 권장된다는 의견이 많습니다. 관리자 UI 처럼 임의 점프가 필요한 자리는 offset.
6. 필터·정렬·검색
관습은 있지만 표준은 아닙니다.
GET /posts?status=published&author=123&sort=-createdAt&search=react
sort=field또는sort=-field(음수 prefix 로 내림차순).q또는search가 자유 텍스트 검색.- 필터는 단순 매개변수로 (
status=published).
복잡한 필터는 별도 표준 (JSON:API · OData · GraphQL) 으로 가기도 합니다.
응답 크기 줄이기 (Sparse Fieldset):
GET /users/123?fields=id,name,email
JSON:API 와 GraphQL 이 표준화한 자리. REST 에서는 관습적입니다.
7. GraphQL · gRPC · tRPC 와의 비교
| 후보 | 자리 |
|---|---|
| REST | 표준·범용. 외부 공개 API 의 다수. |
| GraphQL | 모바일·다양한 클라이언트, 응답 형태가 자주 변하는 자리. |
| gRPC | 내부 서비스 간 통신, 성능·스키마 중요. |
| tRPC | TS 모노레포의 빠른 개발. |
GraphQL (Facebook, 2015) — 클라이언트가 응답 모양을 쿼리로 정의. 장점은 over-fetching · under-fetching 해결, 한 엔드포인트, 강한 스키마. 단점은 캐시 어려움, 학습 곡선, N+1 위험.
gRPC (Google, 2015) — Protobuf 직렬화 + HTTP/2 + 코드 생성. 장점은 매우 빠름, 강한 스키마, 다언어 SDK 자동. 단점은 브라우저에서 직접 사용 어려움, 디버깅 복잡 (바이너리).
tRPC — TypeScript 모노레포에서 클라이언트·서버가 같은 타입을 공유. 장점은 코드 생성 없이 타입 자동 공유, 빠른 개발. 단점은 TypeScript 종속, 다른 언어 클라이언트 어려움.
8. Idempotency-Key · ETag
POST 의 멱등성을 보완하는 관습입니다. Stripe 가 대중화했습니다.
POST /payments
Idempotency-Key: 2025-04-25-abc123
서버가 같은 키의 재요청을 같은 응답으로 처리. 결제·중요 부수 효과 자리에.
ETag 와 If-Match · If-None-Match:
- ETag — 응답에 자원 버전 식별자.
- If-None-Match — 같은 ETag 면 304 Not Modified.
- If-Match — 같은 ETag 일 때만 PUT/DELETE 허용 (낙관적 동시성).
9. 자주 걸리는 자리
POST 로 모든 일 처리 — REST 가 아닙니다. 동사를 URL 에 넣는 흐름이 따라옵니다. 가능한 한 GET/POST/PATCH/DELETE 로 분리합니다.
errors 응답 비표준 — 어떤 곳은 {"error": "..."}, 어떤 곳은 {"message": "..."}. RFC 7807 (application/problem+json) 채택을 검토합니다.
status code 의 부재 — 모든 응답이 200, body 안에 success: false. 클라이언트가 일반 흐름과 오류를 구분하기 어렵습니다.
버저닝 누락 — /v1/users 처럼 URL 또는 헤더 기반 버저닝. 이후 호환 깨질 변경 자리입니다.
N+1 쿼리 — 컬렉션 + 각 항목의 관계를 매번 따로 조회하면 폭주합니다. eager loading · join.
무거운 응답 — 한 번에 1000 행을 반환합니다. 페이지네이션 강제.
CORS — 브라우저에서 서로 다른 origin API 호출 시 preflight. Access-Control-Allow-Origin · -Allow-Methods 점검.
하고픈 말
REST 는 표준이라기보다 관습의 모음입니다. 정답은 없지만 동사를 URL 에 넣지 않는 한두 가지 약속만 지켜도 일관성이 빠르게 보입니다. 외부 공개 API 라면 RFC 7807 + OpenAPI 사양을 함께 두는 편이 운영에 안전합니다.
Next
- websocket-sse
Roy Fielding 박사 논문 · RFC 9110 — HTTP Semantics · RFC 7807 — Problem Details · OpenAPI Spec · GraphQL 공식 · gRPC 공식 을 참고합니다.