"REST API" 라는 말은 거의 모든 백엔드 면접·문서·블로그에 등장한다. 그런데 막상 "REST 가 뭐냐" 물으면 답이 갈린다 — "HTTP + JSON", "URL 에 명사 쓰는 거", "GET/POST 잘 쓰는 거". 셋 다 틀린 답에 가깝다. REST 는 2000 년 Roy Fielding 의 박사 논문에서 정의된 한 아키텍처 스타일이고, 우리가 매일 부르는 "REST API" 의 90% 는 엄밀히 보면 REST 가 아니다. 이 가이드는 진짜 REST 의 원칙, 흔한 오해, Richardson Maturity Model, HATEOAS, 그리고 실전에서 "REST" 라 부르는 것의 정체를 정리한다.
Fielding 의 REST — 6 가지 제약
REST 는 protocol 도 spec 도 아니고 분산 hypermedia 시스템의 아키텍처 스타일. 6 가지 제약을 모두 만족할 때 "RESTful" 이라고 부른다.
1. Client-Server — 관심사 분리 (UI 와 storage 분리)
2. Stateless — 모든 요청에 필요한 모든 정보 포함, 서버 세션 X
3. Cacheable — 응답이 cache 가능한지 명시
4. Uniform Interface — 인터페이스가 표준화 (이게 REST 의 핵심)
5. Layered System — proxy / gateway / LB 가 중간에 있어도 동작
6. Code on Demand — (선택) 서버가 client 에 코드 보낼 수 있음 (JS 등)
이 중 "Uniform Interface" 가 REST 를 REST 답게 하는 차별점.
나머지는 사실 HTTP 자체에 거의 내장.Uniform Interface — REST 의 네 기둥
1. Resource Identification (URI)
/users/42 → "id 42 인 user 라는 resource"
URL 은 resource 식별자, action 식별자 아님.
2. Representation
resource 자체가 아니라 그것의 "표현" 을 주고받음.
같은 user 가 JSON 일 수도, XML 일 수도, HTML 일 수도.
Content-Type / Accept header 로 협상.
3. Self-descriptive Messages
요청 / 응답이 스스로 충분히 설명 — Content-Type, Cache-Control,
상태 코드 (status code) 등 표준 metadata.
4. HATEOAS (Hypermedia As The Engine Of Application State)
응답에 다음 가능한 action 의 link 가 포함.
client 는 link 를 따라가며 navigate — URL 구조를 사전에 알 필요 X.Resource · Method · Representation — 세 축
# Resource
URL 은 명사 (resource 의 식별자), 동사 X
GOOD: /users/42, /orders/77/items
BAD: /getUser?id=42, /createOrder
# Method (HTTP verb 가 action)
GET /users/42 → 조회 (safe, idempotent, cacheable)
POST /users → 생성 (not idempotent)
PUT /users/42 → 전체 교체 (idempotent)
PATCH /users/42 → 부분 수정 (idempotency 는 정의에 따름)
DELETE /users/42 → 삭제 (idempotent)
# Representation
같은 /users/42 가 여러 표현으로:
Accept: application/json → {"id":42,"name":"jade"}
Accept: application/xml → <user id="42">...</user>
Accept: text/html → <h1>jade</h1>
→ URL 은 안 바꾸고 표현만 협상.Idempotency 의 깊은 의미는 idempotency-keys, 상태 코드 결정 트리는 http-status-codes 가이드 참조.
Richardson Maturity Model — REST 의 4 단계
Leonard Richardson 이 제안. API 가 얼마나 REST 에 가까운지 단계로 구분.
Level 0 — "The Swamp of POX" (Plain Old XML)
POST /api → 모든 요청 한 endpoint, body 안에 action 명시
실질적으로 SOAP / RPC over HTTP. URL 도 method 도 의미 없음.
예: { "action": "getUser", "id": 42 }
Level 1 — Resources
/users/42, /orders/77 — URL 이 resource 식별자.
그러나 method 는 여전히 POST 만 (또는 GET/POST 만).
Level 2 — HTTP Verbs
GET /users/42, POST /users, DELETE /users/42 — 표준 method 사용.
status code 도 200/201/404/409 등 의미 있게.
→ 우리가 "REST API" 라 부르는 것의 대부분이 여기 멈춤.
Level 3 — HATEOAS (Hypermedia Controls)
응답에 다음 가능한 action 의 link 포함.
client 가 URL 을 hardcoding 안 함 — 응답을 따라 navigate.
→ 진짜 Fielding 의 REST. 실전에서는 거의 없음.HATEOAS — 가장 안 쓰이는 부분
Level 3 의 예 — 주문 응답에 가능한 다음 action 의 link:
GET /orders/77
{
"id": 77,
"status": "pending_payment",
"total": 50000,
"_links": {
"self": { "href": "/orders/77" },
"pay": { "href": "/orders/77/payment", "method": "POST" },
"cancel": { "href": "/orders/77", "method": "DELETE" }
}
}
client 는 "pay" link 만 보고 POST → URL 구조 사전 지식 X.
장점:
- API 진화에 강함 — URL 바뀌어도 link 만 갱신
- discoverability — 응답이 가능한 다음 단계를 알려줌
왜 안 쓰이나?
- client (특히 SPA) 가 보통 URL 을 hardcoding (성능·UX)
- generic hypermedia client 가 사실상 없음 (브라우저 외)
- 응답 payload 크기 ↑, parse 복잡도 ↑
- 대부분 mobile/web client 는 미리 짜인 화면 흐름 → link 따라가는 의미 X
→ Fielding 본인이 "REST 가 아닌 API 가 REST 라 부르는 것에 짜증" 글
(2008) 을 남겼지만, 업계는 Level 2 에 머묾.Stateless — 가장 자주 깨지는 원칙
Stateless = 서버가 client 의 이전 요청을 기억하면 안 됨
= 모든 요청에 필요한 모든 정보 포함
GOOD:
GET /orders?page=3
Authorization: Bearer <jwt>
→ 모든 정보 (인증·페이지) 가 요청에 있음
BAD (server-side session):
GET /next-page
Cookie: sessionid=abc123
→ 서버가 "abc123 의 마지막 페이지가 뭐였지" 기억해야 함
장점:
- 수평 확장 쉬움 (어떤 서버가 받아도 동일 응답)
- 캐시 효율 ↑
- 실패 시 단순 재시도
함정:
- 인증 token 마다 보내는 비용 (vs 세션 cookie 1 회)
- JWT 의 invalidation 문제 (token 발급 후 권한 변경 반영 어려움)
→ 인증 흐름 자체는 stateless 양립 가능, 단 setup 은 신중.
자세히는 oauth2-explained 가이드."REST 가 아닌데 REST 라 불리는" 흔한 예
# 1. URL 에 동사
POST /users/42/setActive ← action 이 URL 에 있음 (REST 위반)
권장: PATCH /users/42 { "active": true }
# 2. status code 무시
HTTP 200 OK
{ "success": false, "error": "not found" } ← 진짜로 200 응답?
권장: HTTP 404 + body 에 상세
# 3. method 오용
GET /users/42/delete ← GET 이 부수 효과 (safe 위반)
권장: DELETE /users/42
# 4. 응답에 link 없음 (Level 2 한계)
→ 엄밀히는 RESTful 아니지만, 실전 표준.
→ 즉 "REST API" 의 90% 는 Level 2 "HTTP + JSON + 명사 URL".
나쁘다는 게 아니라, 진짜 REST 의 정의를 알고 쓰자는 의미.흔한 오해
- "REST = HTTP" — REST 는 protocol 독립. 이론상 AMQP / WebSocket 위에서도 가능 (실전엔 HTTP 가 거의 100%). HTTP 의 기능 (cache, status code, method) 이 REST 와 잘 맞아서 쓸 뿐.
- "REST = JSON" — representation 은 협상 대상. XML, MessagePack, Protobuf, HTML 모두 가능.
- "PUT 은 update, POST 는 create" — PUT 의 진짜 의미는 idempotent 한 전체 교체 (해당 URI 에 이 representation 으로 박아). create 도 client 가 ID 정하면 PUT 가능.
- "REST 는 stateless 라 인증 못 함" — 인증 정보를 매 요청에 포함 (Bearer token) 하면 양립. 서버 세션을 금지할 뿐.
- "REST 는 GraphQL 보다 옛날 거" — 둘은 다른 문제. REST 는 resource-oriented, GraphQL 은 query-oriented.
how-graphql-actually-works가이드 참조.
실전 REST 의 흔한 트레이드오프
- over-fetching — /users/42 가 모든 field 반환 → mobile 에서 불필요한 byte. sparse fieldsets (?fields=id,name) 또는 GraphQL 로 해결.
- under-fetching (N+1) — list + 각 item 의 detail = N 회 round trip. embed (?include=author) 또는 batch endpoint 로 완화.
- version 관리 — /v1/users, /v2/users 의 path versioning 이 흔함. header (Accept-Version) 도 가능하지만 discoverability 떨어짐.
- pagination 의 일관성 — offset vs cursor 의 트레이드오프는
how-pagination-actually-works가이드. - CORS — 브라우저 client 가 cross-origin 호출 시 preflight + 헤더 협상 필요. 자세히는
cors-explained가이드. - rate limit / abuse — public REST API 에 throttle 필수.
rate-limiting-strategies가이드 참조.
마무리
업계 통념: "REST API = HTTP + JSON + 명사 URL + 표준 method". 그게 Richardson Level 2 — 실용적이고 충분히 좋은 시작점. 그러나 그게 Fielding 의 REST 의 전부는 아니다. HATEOAS / 진짜 hypermedia 까지 가야 Level 3 = REST.
실전에서는 "REST 의 모든 제약 준수" 보다 "팀과 client 가 일관되게 합의한 규칙" 이 더 가치 있다. 메서드 강박·HATEOAS 광신 모두 별 도움 안 됨. 다만 "method 의 의미는 정확히", "status code 는 의미대로", "URL 은 resource 의 식별자" — 이 셋은 거의 무료의 규약.