HTTP PUT과 PATCH 차이
API에서 데이터를 수정할 때 PUT과 PATCH를 자주 만난다.
보통 PUT은 전체 수정, PATCH는 부분 수정이라고 외우지만 이 설명만으로는 요청 본문과 재시도 방식을 판단하기 어렵다.
두 메서드의 차이는 필드 개수가 아니라 서버가 본문을 해석하는 방식에 있다.
PUT 본문은 대상 리소스의 새 상태를 나타내고, PATCH 본문은 현재 상태에 적용할 변경 명령을 나타낸다.
PUT의 교체 의미
PUT은 요청 본문으로 정의한 상태를 대상 리소스의 상태로 생성하거나 교체해 달라는 요청이다.
클라이언트가 변경할 리소스의 URI를 알고 있다는 점도 중요하다.
PUT /users/42 HTTP/1.1
Host: api.example.com
Content-Type: application/json
{
"displayName": "Dohyun",
"email": "dohyun@example.com",
"notifications": true
}이 API가 사용자 JSON 전체를 리소스 표현으로 정의했다면 서버는 본문을 기준으로 /users/42의 상태를 교체한다.
리소스가 새로 만들어졌다면 201 Created, 기존 리소스가 수정됐다면 200 OK나 204 No Content가 일반적인 성공 응답이다.
다만 PUT을 데이터베이스의 모든 열을 덮어쓰는 명령으로 이해하면 안 된다.
서버가 생성하는 ID나 수정 시각처럼 클라이언트 표현에 포함되지 않는 값도 있고, 서버가 본문을 정규화할 수도 있다.
생략한 필드를 삭제할지 기본값으로 채울지는 해당 API가 정의한 리소스 표현과 계약을 확인해야 한다.
PATCH의 변경 명령
PATCH는 본문에 적힌 변경을 현재 리소스에 적용해 달라는 요청이다.
본문 자체가 수정된 리소스의 완성본이 아니라 패치 문서라는 점이 PUT과 다르다.
PATCH /users/42 HTTP/1.1
Host: api.example.com
Content-Type: application/merge-patch+json
{
"displayName": "Hyun"
}JSON Merge Patch 규칙을 따르는 이 요청은 displayName을 바꾸고 나머지 속성은 그대로 둔다.
서버는 패치 전체를 원자적으로 적용해야 하므로 중간 상태를 노출하거나 일부 변경만 남겨서는 안 된다.
PATCH라고 해서 아무 JSON 객체나 보낼 수 있는 것은 아니다.
서버와 클라이언트가 Content-Type으로 패치 문서 형식과 처리 규칙에 합의해야 한다.
멱등성과 재시도 기준
PUT은 HTTP 명세에서 멱등적인 메서드다.
같은 PUT 요청을 여러 번 처리했을 때 클라이언트가 의도한 최종 상태는 한 번 처리한 결과와 같아야 한다.
멱등성은 서버 내부의 모든 부수 효과가 한 번만 발생한다는 뜻은 아니다.
서버는 요청마다 로그를 남기거나 리소스 버전을 기록할 수 있다.
PATCH는 메서드 자체로는 멱등적이지 않다.
값을 같은 값으로 교체하는 패치는 여러 번 적용해도 결과가 같을 수 있지만, 배열 끝에 항목을 추가하는 패치는 실행할 때마다 결과가 달라질 수 있다.
PATCH /documents/7 HTTP/1.1
Host: api.example.com
Content-Type: application/json-patch+json
[
{ "op": "add", "path": "/tags/-", "value": "http" }
]응답을 받기 전에 연결이 끊겼다면 PUT은 메서드 의미를 근거로 재시도를 판단할 수 있다.
PATCH는 같은 요청을 다시 보내도 안전한 연산인지 확인하거나 현재 상태를 다시 조회해야 한다.
패치 문서와 동시 수정
JSON 기반 API에서는 JSON Patch와 JSON Merge Patch가 대표적인 패치 형식이다.
두 형식은 표현 방식과 경계 조건이 다르다.
JSON Patch는 add, remove, replace, move, copy, test 연산을 배열에 순서대로 적는다.
경로는 JSON Pointer 문법을 사용하므로 배열의 특정 위치나 중첩 속성을 명시하기 좋다.
PATCH /users/42 HTTP/1.1
Host: api.example.com
Content-Type: application/json-patch+json
If-Match: "user-42-v3"
[
{ "op": "test", "path": "/email", "value": "dohyun@example.com" },
{ "op": "replace", "path": "/notifications", "value": false }
]JSON Merge Patch는 결과와 비슷한 객체를 보내므로 단순한 객체 속성 수정에 읽기 쉽다.
대신 null은 속성 삭제를 뜻하고 배열 일부만 수정할 수 없어 명시적인 null 값이나 복잡한 배열을 다루는 리소스에는 주의해야 한다.
여러 클라이언트가 같은 리소스를 수정하면 마지막 요청이 앞선 변경을 덮어쓸 수 있다.
이전 응답에서 받은 강한 ETag를 If-Match에 보내면 서버는 현재 ETag가 다를 때 변경을 적용하지 않고 412 Precondition Failed로 충돌을 알릴 수 있다.
선택 기준
클라이언트가 대상 리소스의 새 표현을 알고 있고 같은 요청을 안전하게 재시도해야 한다면 PUT이 잘 맞는다.
현재 표현의 일부를 변경하는 명령만 전달하고 싶다면 서버가 지원하는 패치 형식을 확인한 뒤 PATCH를 사용한다.
필드 몇 개를 보냈는지만 보고 메서드를 정하지 않는다.
리소스 표현, 패치 문서의 미디어 타입, 멱등성, 동시 수정 정책을 함께 API 계약에 적어야 한다.
조회와 생성 요청까지 함께 비교하려면 HTTP GET과 POST 차이를 보면 좋다.
수정 결과와 오류에 사용할 응답 코드는 HTTP 상태 코드 정리에서 이어서 확인할 수 있다.
참고 자료























