RESTful API의 완성도, 리처드슨 성숙도 모델(RMM) 완벽 가이드
REST(Representational State Transfer)는 현대 웹 아키텍처의 근간입니다. 하지만 우리가 실무에서 사용하는 많은 API가 과연 “진정으로 RESTful한가?”라는 질문에는 선뜻 답하기 어렵습니다.
레오나르드 리처드슨(Leonard Richardson)은 API의 REST 원칙 준수 정도를 체계적으로 평가하기 위해 **리처드슨 성숙도 모델(Richardson Maturity Model, RMM)**을 제안했습니다. 이 모델은 API가 얼마나 웹의 잠재력을 활용하고 있는지를 4단계로 나누어 설명합니다.
목차
- Level 0: POX (Plain Old XML) - 원격 프로시저 호출
- Level 1: Resources - 자원의 도입
- Level 2: HTTP Verbs - HTTP 메서드의 활용
- Level 3: Hypermedia Controls - HATEOAS의 구현
- Level 2 vs Level 3: 무엇이 다른가?
- 결론: 로이 필딩의 이상과 현실적인 타협점
Level 0: POX (Plain Old XML) - 원격 프로시저 호출
0단계는 사실상 REST라고 부를 수 없는 단계입니다. HTTP를 단순히 **데이터 전송을 위한 통로(Tunneling)**로만 사용합니다. 모든 요청은 하나의 엔드포인트(Endpoint)로 향하며, 서비스의 기능은 요청 바디에 담긴 내용에 따라 결정됩니다.
HTTP 요청/응답 예시
POST /appointmentService HTTP/1.1
Content-Type: application/xml
<getSchedule>
<doctor>doctor_kim</doctor>
<date>2026-03-10</date>
</getSchedule>
- 특징: 단일 URI, 단일 HTTP 메서드(주로 POST) 사용.
- 문제점: 서비스가 복잡해질수록 관리 포인트가 단일 엔드포인트에 집중되어 유지보수가 어렵고, HTTP의 풍부한 기능을 전혀 활용하지 못합니다.
Level 1: Resources - 자원의 도입
1단계의 핵심은 자원(Resource)의 개별화입니다. 모든 요청을 하나의 엔드포인트로 보내는 대신, 개별 자원에 고유한 URI를 부여합니다.
HTTP 요청/응답 예시
POST /doctors/kim HTTP/1.1
Content-Type: application/json
{
"date": "2026-03-10",
"action": "getSlots"
}
- 특징:
doctors/kim,doctors/park처럼 자원별로 고유한 주소를 가집니다. - 발전 방향: “무엇을(Resource)” 조작하는지에 대한 개념이 생겼지만, 여전히 “어떻게(Verb)” 조작하는지에 대해서는 HTTP 메서드를 충분히 활용하지 못하고 여전히 POST에 의존하는 경향이 있습니다.
Level 2: HTTP Verbs - HTTP 메서드의 활용
우리가 흔히 ‘RESTful API’라고 부르는 대부분의 서비스가 속하는 단계입니다. 자원의 주소뿐만 아니라, HTTP 표준 메서드(GET, POST, PUT, DELETE)를 목적에 맞게 사용합니다. 또한, HTTP 상태 코드(Status Codes)를 통해 요청의 성공/실패 여부를 정확히 전달합니다.
HTTP 요청/응답 예시
GET /doctors/kim/slots?date=2026-03-10 HTTP/1.1
---
HTTP/1.1 200 OK
Content-Type: application/json
[
{"id": 1, "start": "09:00", "end": "10:00"},
{"id": 2, "start": "10:00", "end": "11:00"}
]
💡 개발자의 팁: 상태 코드의 올바른 활용
실무에서 가장 흔한 실수 중 하나는 에러가 발생했음에도 바디에 에러 메시지를 담아
200 OK를 반환하는 것입니다. 2단계의 핵심은 인프라(프록시, 캐시 서버 등)가 HTTP 프로토콜 수준에서 요청의 결과를 이해하도록 하는 것입니다. 잘못된 요청에는400 Bad Request, 권한이 없을 땐403 Forbidden을 명확히 반환하세요.
Level 3: Hypermedia Controls - HATEOAS의 구현
마지막 단계는 **HATEOAS(Hypermedia As The Engine Of Application State)**를 적용하는 것입니다. 응답 데이터에 **다음에 수행할 수 있는 작업에 대한 링크(Link)**를 포함합니다. 클라이언트는 서버가 제공하는 링크를 따라가며 애플리케이션의 상태를 전이시킵니다.
HTTP 요청/응답 예시
POST /appointments HTTP/1.1
Content-Type: application/json
{
"slotId": 1,
"patient": "lee"
}
---
HTTP/1.1 201 Created
Content-Type: application/json
{
"id": 123,
"status": "confirmed",
"links": [
{ "rel": "self", "href": "/appointments/123" },
{ "rel": "cancel", "href": "/appointments/123/cancel", "method": "DELETE" },
{ "rel": "reschedule", "href": "/appointments/123/reschedule", "method": "POST" }
]
}
Level 2 vs Level 3: 무엇이 다른가?
실무진들 사이에서 가장 논쟁이 많은 지점입니다. 핵심적인 차이를 대조해 보겠습니다.
| 구분 | Level 2 (HTTP Verbs) | Level 3 (HATEOAS) |
|---|---|---|
| 클라이언트의 지식 | API 문서(Swagger 등)에 정의된 URI 구조를 미리 알고 있어야 함. | 서버가 보내준 링크를 통해 동적으로 다음 동작 URI를 파악함. |
| 결합도(Coupling) | 서버의 URI 구조가 바뀌면 클라이언트 코드도 함께 수정되어야 함. | 서버가 링크만 바꿔주면 클라이언트는 수정 없이 새로운 경로로 접근함. |
| 자기 설명력 | 데이터 자체만 전달하며, 다음 행위는 비즈니스 로직에 의존함. | 응답 안에 ‘할 수 있는 일’이 포함되어 API 자체가 가이드 역할을 함. |
결론: 로이 필딩의 이상과 현실적인 타협점
REST의 창시자 **로이 필딩(Roy Fielding)**은 “HATEOAS를 만족하지 않는 API는 REST API가 아니다”라고 단언했습니다. 즉, 엄밀히 말하면 우리가 만드는 대부분의 서비스는 ‘HTTP API’일 뿐 ‘REST API’가 아닌 셈입니다.
하지만 실무에서는 다음과 같은 이유로 2단계에 머무르는 경우가 많습니다:
- 개발 비용: 모든 응답에 대해 현재 상태에서 가능한 링크를 생성하고 관리하는 것은 오버헤드가 큽니다.
- 클라이언트 구현: 링크를 동적으로 해석하는 구조는 프론트엔드 코드의 복잡성을 높일 수 있습니다.
- 대체 수단: Swagger(OpenAPI)와 같은 도구가 이미 API 구조를 충분히 잘 설명해 주기 때문에 굳이 링크를 넣지 않아도 소통에 문제가 없습니다.
결론적으로, 모든 프로젝트에 3단계를 강요할 필요는 없습니다. 하지만 시스템의 결합도를 낮추고 진화 가능한 아키텍처를 원한다면, RMM의 각 단계를 이해하고 점진적으로 도입해보는 경험은 시니어 개발자로 가는 중요한 밑거름이 될 것입니다.
🚀 실무 API 설계 체크리스트
- 자원은 명사형으로 표현하며, 복수형(Plural)을 사용하였는가?
- HTTP 메서드(GET, POST, PUT, DELETE)가 행위의 목적에 부합하는가?
- 성공 시
200/201, 실패 시4xx/5xx등 의미에 맞는 상태 코드를 반환하는가? - (권장) 클라이언트가 다음 상태를 알기 위해 복잡한 하드코딩이 필요한가? -> HATEOAS 도입 검토
FAQ
Q. HATEOAS를 구현하기 위한 표준 라이브러리가 있나요?
Java 진영에서는 Spring HATEOAS가 대표적이며, Node.js나 Python 환경에서는 HAL(Hypertext Application Language) 포맷을 지원하는 라이브러리를 주로 활용합니다.
Q. Level 2만 구현해도 실무에서 문제가 없나요?
네, 대다수의 엔터프라이즈 서비스와 오픈 API들이 Level 2 수준의 설계에 문서화를 결합하여 성공적으로 운영되고 있습니다.
Q. URI에 ‘get’, ‘delete’ 같은 동사를 포함하면 안 되나요?
REST 원칙에 따르면 행위는 HTTP 메서드로 표현해야 합니다. /getUsers 보다는 GET /users가 더 바람직하며 확장성 있는 설계입니다.
더 자세한 정보는 Martin Fowler의 리처드슨 성숙도 모델 원문에서 확인하실 수 있습니다.
댓글을 불러오는 중...