Skip to content
HTTP 기초제 5장

HTTP 메서드는 API 설계에서 어떤 의미를 갖고 어떻게 선택할까?

05. HTTP 메서드와 API 설계


학습 목표

  1. URI가 리소스(명사)를 식별하고, 메서드가 행위(동사)를 표현한다는 원칙을 설명할 수 있다.
  2. GET, POST, PUT, PATCH, DELETE의 역할 차이를 구분할 수 있다.
  3. PUTPATCH를 왜 혼동하면 안 되는지 이해할 수 있다.
  4. 안전, 멱등, 캐시 가능 속성이 실무에서 왜 중요한지 설명할 수 있다.
  5. document, collection, store, controller URI 패턴을 API 설계에 적용할 수 있다.

전체 구조


1. 왜 URI에 동사를 넣으면 설계가 꼬일까?

회원 관리 API를 만든다고 해보자. 초반에는 보통 이런 식으로 이름을 짓고 싶어진다.

  • /read_member_list
  • /read_member_by_id
  • /createMember
  • /updateMember
  • /deleteMember

처음 보면 읽기 쉬워 보인다.
그런데 이런 방식은 리소스행위를 한 경로에 뒤섞는다.

여기서 우리가 진짜 다루는 대상은 무엇일까?

  • 조회
  • 등록
  • 수정
  • 삭제

이것들은 행위다.

  • 회원
  • 주문
  • 파일

이것들이 리소스다.

즉, URI는 “무엇을 다루는가”만 식별해야 하고, “무슨 행동을 할 것인가”는 HTTP 메서드가 맡는 편이 훨씬 자연스럽다.

리소스 중심 설계의 핵심

회원 목록은 여러 회원이 모인 집합이므로 보통 복수형 컬렉션으로 설계한다.

text
/members
/members/{memberId}

그 다음 동작은 메서드가 표현한다.

하고 싶은 일URI메서드
회원 목록 조회/membersGET
회원 한 명 조회/members/{memberId}GET
회원 등록/membersPOST
회원 부분 수정/members/{memberId}PATCH
회원 삭제/members/{memberId}DELETE

핵심 직관: URI는 “대상”을 가리키고, HTTP 메서드는 “행동 기대치”를 가리킨다.


2. HTTP 메서드는 무엇을 맡을까?

메서드는 클라이언트가 서버에 “이 리소스를 이런 식으로 다뤄주길 기대한다”는 신호다.

메서드기본 의미대표 예시바디 사용기억할 점
GET리소스 조회GET /members/100보통 안 씀조회 전용, 쿼리 파라미터와 궁합이 좋음
POST요청 데이터 처리POST /members주로 사용생성, 프로세스 처리, 예외적 동작까지 담당
PUT대상 리소스 전체 대체PUT /files/report.pdf주로 사용없으면 생성될 수 있고, 있으면 덮어씀
PATCH대상 리소스 부분 변경PATCH /members/100주로 사용일부 필드만 바꿀 때 적합
DELETE대상 리소스 삭제DELETE /members/100거의 안 씀같은 삭제 요청 반복에 강함

2-1. GET: 조회 전용 메서드

GET은 말 그대로 리소스를 조회할 때 쓴다.

http
GET /members/100 HTTP/1.1

검색, 정렬, 필터처럼 추가 조건이 필요하면 보통 쿼리 파라미터를 붙인다.

text
GET /members?role=admin&sort=name

GET에서 기억할 점

  • 조회이므로 리소스를 바꾸지 않는 방향으로 사용한다.
  • 검색 조건은 보통 쿼리 파라미터로 전달한다.
  • 스펙상 GET 바디를 완전히 금지한다고만 보긴 어렵지만, 실무에서는 호환성 문제 때문에 사용하지 않는 쪽이 안전하다.

2-2. POST: 생성만이 아니라 “처리 요청” 전체를 담당

POST는 단순히 “새 데이터 생성”만 의미하지 않는다.
핵심은 요청 본문을 서버가 받아서 처리해 달라는 것이다.

http
POST /members HTTP/1.1
Content-Type: application/json

{
  "name": "mia",
  "age": 20
}

가장 대표적인 활용은 새 리소스 생성이다.
이 경우 보통 서버가 새 URI를 만든다.

POST를 쓰는 대표 상황

  • 새 회원 등록
  • 주문 생성
  • 게시글 작성
  • 댓글 작성
  • 복잡한 프로세스 실행
  • 메서드만으로 표현하기 어려운 추가 동작 처리

예를 들어 “배송 시작” 같은 동작은 단순 CRUD로 딱 떨어지지 않을 수 있다.

text
POST /orders/100/delivery

이 경우 POST는 “주문 100번의 배송 시작 프로세스를 실행해 달라”는 의미에 가깝다.

2-3. PUT: 대상 URI를 기준으로 전체를 갈아끼운다

PUT은 대상 URI에 있는 리소스를 통째로 대체한다.

http
PUT /files/report.pdf HTTP/1.1
Content-Type: application/pdf

(binary data)

이 메서드의 핵심은 두 가지다.

  • 클라이언트가 어디에 저장할지 URI를 알고 있다
  • 서버는 그 URI의 리소스를 새것으로 대체한다

즉, 리소스가 없으면 새로 생성될 수 있고, 이미 있으면 기존 내용을 덮어쓴다.

PUT을 쓸 때 주의할 점

PUT은 부분 수정이 아니다.
전체 replacement에 가깝다.

예를 들어 회원 정보에 name, age, email이 있는데 name만 보내면, 서버 설계에 따라 나머지 필드가 사라질 수 있다.
그래서 전체 상태를 자신 있게 보낼 수 있을 때 더 적합하다.

2-4. PATCH: 필요한 필드만 일부 바꾼다

PATCH는 리소스의 일부분만 변경할 때 쓴다.

http
PATCH /members/100 HTTP/1.1
Content-Type: application/json

{
  "age": 31
}

이 요청은 “회원 전체를 다시 보내겠다”가 아니라, “이 필드만 바꾸겠다”에 가깝다.

PATCH가 유리한 이유

  • 일부 필드만 보낼 수 있다
  • 전체 데이터 유실 위험이 적다
  • 실무의 수정 시나리오와 더 잘 맞는다

다만 환경에 따라 PATCH 지원이 애매한 경우가 있어, 그런 경우에는 POST로 보완하기도 한다.

2-5. DELETE: 대상 리소스를 제거한다

DELETE는 지정한 리소스를 삭제할 때 쓴다.

http
DELETE /members/100 HTTP/1.1

의미는 단순하다.

  • 대상은 /members/100
  • 기대 동작은 “이 리소스를 없애 달라”

실무에서는 삭제 후 실제로 완전 삭제할지, 논리 삭제 상태로 바꿀지는 서버 구현 정책에 달려 있다.
하지만 HTTP 관점에서 DELETE는 “삭제 의도”를 표현하는 데 적합하다.


3. 메서드 속성은 왜 중요할까?

HTTP 메서드는 단순히 이름만 다른 것이 아니라, 재시도와 캐시 전략에 영향을 주는 속성을 가진다.

3-1. 안전(Safe): 호출해도 리소스가 바뀌지 않는가?

안전하다는 것은 호출해도 대상 리소스 상태가 변경되지 않는다는 뜻이다.

  • 대표적으로 GET, HEAD
  • POST, PUT, PATCH, DELETE는 안전하지 않다

중요한 점은 “로그가 쌓이느냐”, “통계가 증가하느냐” 같은 부수 효과까지 따지지 않는다는 것이다.
핵심은 대상 리소스가 바뀌는가다.

3-2. 멱등(Idempotent): 같은 요청을 여러 번 보내도 최종 상태가 같은가?

멱등은 많이 헷갈리지만, 기준은 단순하다.

같은 요청을 한 번 보내든 여러 번 보내든, 서버의 최종 상태가 같으면 멱등하다.

  • GET: 여러 번 조회해도 상태를 바꾸지 않으므로 멱등
  • PUT: 같은 전체 데이터를 여러 번 덮어써도 최종 상태가 같으므로 멱등
  • DELETE: 여러 번 삭제 요청을 보내도 최종 상태는 “삭제됨”이므로 멱등
  • POST: 같은 주문 생성, 같은 결제 요청을 두 번 보내면 중복 생성/중복 결제가 생길 수 있어 보통 멱등이 아님

멱등에서 중요한 것은 동일한 요청 자체다.
중간에 다른 사용자가 리소스를 바꾸는 외부 요인까지 포함해서 판단하지는 않는다.

또 한 가지 더 기억할 점이 있다.

  • 멱등은 최종 상태 기준이다
  • 응답 코드나 응답 바디가 항상 완전히 같아야 한다는 뜻은 아니다

3-3. 캐시 가능(Cacheable): 응답을 재사용하기 쉬운가?

캐시 가능성은 응답을 저장해 두고 다시 활용할 수 있느냐와 관련된다.

실무에서는 이렇게 이해하면 충분하다.

  • 스펙상 범위는 더 넓게 볼 수 있다
  • 하지만 실제 캐시는 거의 GET, HEAD 중심으로 생각하면 된다

이유는 단순하다.

  • GET은 URL만으로 같은 요청을 식별하기 쉽다
  • POST, PATCH는 바디 내용까지 함께 고려해야 해서 구현이 복잡하다

그래서 조회 API를 굳이 POST로 설계하면, 캐시 이점을 스스로 버리게 되는 경우가 많다.

메서드 속성 한눈에 보기

메서드안전멱등캐시 실무 활용
GET매우 높음
POST아니오아니오낮음
PUT아니오거의 없음
PATCH아니오보통 아님거의 없음
DELETE아니오거의 없음

실무 감각: 조회는 GET으로 보내야 캐시와 재시도 전략을 자연스럽게 가져갈 수 있다.


4. API 설계를 더 명확하게 만드는 네 가지 개념

리소스 중심 설계를 더 정리해서 보면 보통 네 가지 패턴으로 이해할 수 있다.

4-1. Document: 하나의 리소스

문서는 단일 리소스를 가리킨다.

  • /members/100
  • /files/report.pdf

즉, “한 개의 회원”, “한 개의 파일”처럼 하나를 정확히 집는 경로다.

4-2. Collection: 서버가 URI를 관리하는 집합

컬렉션은 서버가 관리하는 리소스 집합이다.

  • /members
  • /orders

보통 새 리소스를 등록할 때 POST를 보낸다.

text
POST /members

그러면 서버가 새 ID를 만들고, 생성된 URI를 응답으로 알려준다.

http
HTTP/1.1 201 Created
Location: /members/100

즉, 컬렉션에서는 서버가 새 리소스 URI를 결정한다.

4-3. Store: 클라이언트가 URI를 알고 관리하는 저장소

스토어는 클라이언트가 대상 URI를 이미 알고 있는 경우에 가깝다.

text
PUT /files/report.pdf

이 경우 클라이언트는 “report.pdf라는 이름으로 여기에 저장하겠다”를 이미 알고 있다.
서버는 그 URI 위치에 생성하거나 덮어쓴다.

즉, 스토어에서는 클라이언트가 URI를 결정한다.

4-4. Controller URI: 리소스만으로 표현이 안 될 때 쓰는 보조 수단

이상적으로는 리소스 + 메서드만으로 충분하면 가장 좋다.
하지만 실무에서는 그렇게 깔끔하게 끝나지 않는 경우가 많다.

예:

  • POST /orders/100/delivery
  • POST /members/100/delete
  • POST /members/100/upgrade

이런 URI는 “추가 프로세스 실행”에 가깝다.
그래서 보통 동사를 직접 경로에 넣는다.

Controller URI를 쓸 때 기준

  • 먼저 document/collection 구조로 해결을 시도한다
  • 그래도 표현이 안 되면 마지막 수단으로 controller URI를 쓴다
  • 동작을 표현하므로 보통 POST와 함께 쓰는 경우가 많다

중요한 기준: controller URI는 편해서 먼저 쓰는 것이 아니라, 리소스 중심 설계로 해결이 안 될 때 보조적으로 써야 한다.


5. 실무에서 메서드를 고르는 기준

API를 설계할 때는 아래 순서로 생각하면 크게 흔들리지 않는다.

  1. 먼저 URI에서 동사를 지우고 리소스 이름만 남겨 본다.
  2. 목록인지 단건인지 구분해서 collectiondocument 구조를 만든다.
  3. 조회면 GET, 생성이면 POST, 전체 대체면 PUT, 부분 수정이면 PATCH, 삭제면 DELETE를 우선 검토한다.
  4. PUT을 쓰려면 “클라이언트가 전체 상태를 정말 보낼 수 있는가?”를 먼저 확인한다.
  5. 메서드만으로 표현하기 어려운 추가 프로세스가 남으면 controller URI를 제한적으로 사용한다.

핵심 암기 포인트

  • URI는 리소스(명사)를 식별하고, 행위는 HTTP 메서드가 표현한다.
  • GET은 조회, POST는 처리 요청, PUT은 전체 대체, PATCH는 부분 변경, DELETE는 삭제다.
  • PUT은 일부 수정용이 아니라 전체 교체용으로 이해해야 안전하다.
  • POST /members는 서버가 URI를 만드는 컬렉션 스타일이고, PUT /files/report.pdf는 클라이언트가 URI를 아는 스토어 스타일이다.
  • controller URI는 리소스 중심 설계로 해결되지 않을 때만 보조적으로 사용한다.
  • 조회 API를 GET으로 설계해야 캐시와 재시도 전략을 자연스럽게 가져갈 수 있다.

확인 질문

  1. /createMember보다 POST /members가 더 좋은 설계일까?
  2. PUTPATCH의 가장 큰 차이는 무엇일까?
  3. POST가 “생성 전용 메서드”가 아닌 이유는 무엇일까?
  4. DELETE는 멱등이고, POST는 보통 멱등이 아닐까?
  5. collection, store, controller URI는 각각 언제 쓰는 것이 자연스러울까?