Skip to Content
HTTP / REST

HTTP / REST API 설계

REST는 화려한 기술이 아니라 ‘약속’이다. HTTP가 이미 정의해 둔 메서드와 상태 코드의 의미를 지키면, 별도 문서 없이도 클라이언트가 API의 동작을 예측할 수 있다. 그 약속의 핵심을 정리한다.
1

HTTP 메서드 의미론

메서드는 ‘리소스에 무엇을 할 것인가’를 나타낸다. 동작을 URL에 담지 않고 (예: /users/delete) 메서드로 표현하는 것이 REST의 출발점이다.

메서드의미예시
GET리소스 조회GET /users/42
POST리소스 생성POST /users
PUT리소스 전체 교체PUT /users/42
PATCH리소스 부분 수정PATCH /users/42
DELETE리소스 삭제DELETE /users/42

PUT vs PATCH

PUT은 리소스를 통째로 교체하므로 보내지 않은 필드는 비워진다고 본다. PATCH는 보낸 필드만 부분 수정한다. 수정 폼에서 일부만 보낸다면 PATCH가 의미상 맞다.

2

멱등성과 안전성

API를 견고하게 만들려면 각 메서드의 ‘안전성(safe)’과 ‘멱등성(idempotent)’을 이해해야 한다. 특히 네트워크 재시도 상황에서 중요하다.

안전(Safe)

서버 상태를 바꾸지 않는 메서드다. GET이 대표적이다. 안전한 메서드는 자유롭게 캐싱하고 미리 가져올 수 있다.

멱등(Idempotent)

같은 요청을 여러 번 보내도 결과가 동일한 메서드다. GET·PUT·DELETE는 멱등하지만, POST는 호출할 때마다 새 리소스를 만들어 멱등하지 않다.

재시도와 중복 생성

네트워크 타임아웃으로 POST를 재시도하면 리소스가 중복 생성될 수 있다. 결제·주문 같은 곳에서는 멱등성 키(Idempotency-Key)를 헤더로 받아 중복을 막는다.

3

상태 코드 체계

상태 코드는 응답의 결과를 한눈에 알려주는 신호다. 200으로 뭉뚱그리고 본문에{ success: false }를 넣는 방식은 HTTP의 의미를 버리는 안티패턴이다.

분류의미대표 코드
2xx성공200 OK · 201 Created · 204 No Content
3xx리다이렉션301 Moved · 304 Not Modified
4xx클라이언트 오류400 · 401 · 403 · 404 · 409
5xx서버 오류500 Internal · 503 Unavailable

자주 헷갈리는 코드

401은 인증 안 됨(누구인지 모름), 403은 인증은 됐지만 권한 없음. 409 Conflict는 중복 가입처럼 현재 상태와 충돌할 때 쓴다.

201과 Location

생성 성공 시 201 Created와 함께 Location 헤더에 새 리소스의 URI를 담아주면 클라이언트가 바로 접근할 수 있다.

4

RESTful 리소스 설계

URI는 ‘행위’가 아니라 ‘자원(명사)’을 가리켜야 한다. 행위는 메서드가, 대상은 URI가 표현한다.

리소스 설계 비교
# ❌ 동사·행위가 URI에 노출
POST /createUser
GET  /getUserOrders?userId=42
POST /users/42/delete

# ✅ 명사(자원) 중심, 계층 구조
POST   /users                  # 사용자 생성
GET    /users/42               # 단일 조회
GET    /users/42/orders        # 하위 컬렉션
DELETE /users/42               # 삭제
  • 컬렉션은 복수형: /users, /orders처럼 복수 명사로 통일한다.
  • 계층으로 소유 관계 표현: /users/42/orders는 42번 사용자의 주문을 의미한다.
  • 필터·정렬·페이징은 쿼리스트링: /orders?status=paid&sort=-createdAt&page=2처럼 자원의 부분 집합을 쿼리로 표현한다.
5

RFC 7807 에러 형식

에러 응답 형식이 API마다 제각각이면 클라이언트가 매번 다르게 파싱해야 한다. RFC 7807(Problem Details)은 에러 본문의 표준 형태를 정의해 이 문제를 해결한다.

application/problem+json
HTTP/1.1 409 Conflict
Content-Type: application/problem+json

{
  "type": "https://api.example.com/errors/duplicate-email",
  "title": "이미 사용 중인 이메일입니다",
  "status": 409,
  "detail": "user@example.com 은 이미 가입된 이메일입니다.",
  "instance": "/users"
}

표준 필드

type(에러 종류 URI), title(요약), status(HTTP 코드), detail(상세), instance(발생 위치)로 구성된다. 도메인별 필드는 자유롭게 확장한다.

일관성의 가치

모든 에러가 같은 형태를 가지면, 클라이언트는 공통 에러 핸들러 하나로 모든 에러를 처리할 수 있다. 계약(contract)이 명확해진다.

좋은 API는 새 문서를 읽지 않아도 동작이 예측된다.
메서드·상태 코드·자원이라는 HTTP의 약속을 그대로 지키는 것이 곧 REST다.