REST API 설계: 자원 지향 아키텍처로 안정적인 인터페이스 만들기
REST는 자원과 URI, HTTP 메서드 의미론, 무상태성과 캐시, 계층화, 하이퍼미디어를 결합한 API 아키텍처 스타일이다. 동시성 제어부터 버전 관리, 오류 모델까지 실무 설계 기준을 정리한다.
2026-08-12 · 최초 발행 2025-11-26
URI에 동사를 넣지 않는 이유
REST(Representational State Transfer)는 분산 시스템에서 자원(Resource)의 상태 표현을 HTTP 표준으로 교환하는 아키텍처 스타일이다. 자원 식별자(URI), 표현(JSON/XML), HTTP 메서드 의미론, 무상태성, 캐시, 계층화, 일관 인터페이스로 구성된다.
서비스를 설계할 때 기본 단위는 세 가지로 나뉜다. 자원(명사)은 URI로 표현하고(/orders, /orders/{id}), 행위(동사)는 HTTP 메서드로 표현하며(GET, POST, PUT, PATCH, DELETE), 표현(컨텐츠 타입)은 JSON/XML 등으로 Content-Type/Accept 헤더를 통해 협상한다. Resource Oriented Architecture(ROA)는 자원 컬렉션과 개별 자원을 명확히 구분하고, URI로 위치·관계를 표현하는 모델이다. 자원 간 링크로 탐색이 가능하도록 설계한다.
URI 설계 원칙은 명사 기반, 복수형 컬렉션(/users), 계층 관계 반영(/users/{id}/orders)이다. 동사는 URI에서 배제하고 HTTP 메서드로 표현한다. 식별자는 표현과 분리해 안정성을 유지한다 — URI는 자원을 가리키고, Accept/Content-Type은 표현 유형을 분리해서 다룬다.
HTTP 메서드 의미론과 무상태성
GET(조회, 안전·멱등), POST(생성/액션, 비멱등), PUT(전체 갱신, 멱등), PATCH(부분 갱신, 비멱등), DELETE(삭제, 멱등)의 의미론을 지키는 것이 REST API의 문법이다. Accept, Content-Type 헤더로 JSON/XML 등 표현을 협상하고, 상태 코드는 2xx/4xx/5xx 범주로 표준화해 클라이언트의 제어 흐름을 단순화한다.
무상태성은 서버가 세션을 보관하지 않는 원칙이다. 상태는 클라이언트가 보유하거나 토큰(JWT 등)으로 전달한다. Cache-Control, ETag/If-None-Match, Last-Modified/If-Modified-Since 같은 캐시 헤더로 캐시 적중률을 높이고 백엔드 부하를 줄인다. 캐시 히트율 60%를 가정하면 백엔드 요청은 40%로 줄어든다.
계층화·보안·하이퍼미디어
API Gateway나 Reverse Proxy를 통한 레이어링으로 확장성과 보안을 강화한다. Rate Limit, Circuit Breaker, Observability를 이 계층에 삽입하기 쉬워진다. TLS를 강제하고 OAuth 2.0/OIDC 기반 인증·인가, 스코프/권한 분리로 최소권한 원칙을 지킨다.
HATEOAS 원칙은 응답 안에 링크(self, next, related)를 제공해 클라이언트가 링크를 따라 상호작용 흐름을 발견하게 한다. HAL/JSON:API 같은 스키마를 채택하면 일관된 응답 구조와 도구 호환성을 확보할 수 있다.
요청이 처리되는 흐름
요청은 인증/인가 → 입력 검증 → 사전 조건(ETag) → 트랜잭션/락 → 도메인 로직 순서로 처리되고, 적절한 상태 코드와 캐시/동시성 헤더를 담아 응답한다.
입력은 URI 경로/쿼리, Method, 헤더(Accept, Content-Type, If-Match 등), Body(JSON 등)로 구성된다. 처리는 인증/인가 → 유효성 검증 → 사전 조건(ETag) → 트랜잭션/락 → 도메인 로직 순서로 진행하고, 출력은 적절한 상태 코드, 에러 세부(문제 상세), 캐시/동시성 헤더를 포함한다.
설계 요소가 운영 지표에 미치는 영향
| 설계 요소 | 성능 | 확장성 | 일관성 | 안정성 | 운영 편의 |
|---|---|---|---|---|---|
| 무상태성 | 서버 세션 부하 감소 | 수평 확장 용이 | 클라이언트 상태 책임 증가 | 장애 격리 용이 | 배포/스케일 단순화 |
| 캐시 제어(ETag/TTL) | 응답 지연 감소 | 백엔드 트래픽 완화 | 캐시 불일치 관리 필요 | 다운스트림 장애 시 완충 | 캐시 정책으로 운영 제어 |
| 멱등성/안전성 준수 | 재시도 비용 최소화 | 대규모 재시도에도 부작용 억제 | 반복 호출 시 결과 일관 | 네트워크 실패 내성 향상 | 운영 자동화/재시도 단순화 |
| 계층화(API GW/Proxy) | 공통 기능 오프로드 | 라우팅/샤딩 유연 | 정책 일괄 적용 | 서킷브레이커로 보호 | 로깅/모니터링 집중화 |
| 하이퍼미디어/표준 스키마 | 클라이언트 로직 경량 | 버전 변화 흡수 | 링크 기반 흐름 일관 | 프로토콜 진화 안정 | 문서화/도구 호환 용이 |
CRUD 설계와 동시성 제어
컬렉션과 개별 자원을 분리해 설계한다: POST /orders, GET /orders/{id}, PUT/PATCH /orders/{id}, DELETE /orders/{id}. ETag 기반 갱신은 If-Match 헤더로 조건부 업데이트를 수행해 레이스 조건을 막는다(불일치 시 412 반환).
아래는 curl 7.x 이상, JSON/UTF-8을 지원하는 서버를 전제로 한 실행 예시다.
# 생성
curl -i -X POST https://api.example.com/orders \
-H "Content-Type: application/json" \
-d '{"itemId":"SKU123","qty":2}'
# 조회
curl -i -X GET https://api.example.com/orders/100 \
-H "Accept: application/json"
# 조건부 갱신(ETag 사용)
curl -i -X PUT https://api.example.com/orders/100 \
-H "Content-Type: application/json" \
-H 'If-Match: "etag-abc123"' \
-d '{"qty":3}'
# 삭제(멱등)
curl -i -X DELETE https://api.example.com/orders/100
페이징부터 오류 모델까지
표준 쿼리 파라미터 page, size, sort, filter를 사용한다(GET /orders?page=2&size=50&sort=createdAt,desc). 응답에는 페이지 메타와 Link 헤더(next, prev)를 제공하고, 대량 데이터는 키셋 페이징을 고려한다(속도·안정성 우수).
버전 관리는 URI 버전(/v1)이 간결하고 캐싱이 쉬우며, 헤더 버전(Accept: application/vnd.example.v2+json)은 더 세밀한 협상이 가능하다. 하위 호환은 추가로만 하고, 파괴적 변경은 새 버전으로 발행하며 공존 기간과 마이그레이션 가이드를 명시한다.
오류 모델은 RFC 7807(problem+json)을 채택해 type, title, status, detail, instance 필드를 통일한다. 상관 ID(Correlation-Id)를 로깅하고 RateLimit 헤더(X-RateLimit-*)를 노출하며, 재시도-지수백오프 가이드를 함께 제공한다.
보안은 OAuth 2.0 Client Credentials/Authorization Code와 스코프 세분화를 적용한다. 입력 검증과 출력 인코딩, 서명된 토큰의 만료·회전 정책, 최소권한과 원천 IP 제한을 병행한다.
REST는 CRUD 중심 업무 도메인에 특히 잘 맞는다. 멱등성, 사전 조건, 표준 오류 모델을 도입하면 운영 신뢰성이 강해지고, 조직 차원의 URI·응답 규약과 버전·보안·관측성 표준을 함께 세우면 일관된 API 시스템을 구축할 수 있다.