REST API 실제 시나리오에서 PUT 및 PATCH 메소드 사용


681

우선, 일부 정의 :

PUT은 섹션 9.6 RFC 2616에 정의되어 있습니다 .

PUT 메소드는 동봉 된 엔티티가 제공된 Request-URI 아래에 저장되도록 요청합니다. Request-URI가 이미 존재하는 자원을 참조하는 경우 동봉 된 엔티티 는 원본 서버에있는 수정 된 버전으로 간주해야합니다 . Request-URI가 기존 자원을 가리 키지 않고 요청 사용자 에이전트가 해당 URI를 새 자원으로 정의 할 수있는 경우, 오리진 서버는 해당 URI로 자원을 작성할 수 있습니다.

PATCH는 RFC 5789에 정의되어 있습니다 .

PATCH 메소드 는 요청 엔티티에 설명 된 일련의 변경 사항 이 요청 URI에 의해 식별 된 자원에 적용되도록 요청합니다.

또한 RFC 2616 섹션 9.1.2 에 따르면 PUT은 Idempotent이지만 PATCH는 그렇지 않습니다.

이제 실제 예를 살펴 보겠습니다. /users데이터로 POST를 수행 {username: 'skwee357', email: 'skwee357@domain.com'}하고 서버가 리소스를 만들 수 있으면 201 및 리소스 위치 (응답)로 응답하고 /users/1다음에 GET /users/1을 호출 하면 반환 {id: 1, username: 'skwee357', email: 'skwee357@domain.com'}됩니다.

이제 이메일을 수정하고 싶다고하겠습니다. 이메일 수정은 "변경 세트"로 간주되므로 /users/1" 패치 문서 "로 패치 해야합니다 . 제 경우에는 json 문서가 될 것 {email: 'skwee357@newdomain.com'}입니다. 그런 다음 서버는 200을 반환합니다 (허가가 있다고 가정). 이것은 나를 첫 번째 질문으로 인도합니다.

  • 패치는 dem 등성이 아닙니다. RFC 2616 및 RFC 5789에 나와 있습니다. 그러나 새 이메일과 동일한 PATCH 요청을 발행하면 동일한 리소스 상태 (내 이메일이 요청 된 값으로 수정 됨)를 얻게됩니다. PATCH가 i 등성이 아닌 이유는 무엇입니까?

PATCH는 비교적 새로운 동사 (2010 년 3 월에 도입 된 RFC)이며 "패치"또는 필드 집합 수정 문제를 해결합니다. PATCH가 소개되기 전에 모두 PUT을 사용하여 리소스를 업데이트했습니다. 그러나 PATCH가 소개 된 후 PUT이 무엇인지에 대해 혼란스러워했습니다. 그리고 이것은 나의 두 번째 (그리고 주요) 질문으로 나를 데려옵니다.

  • PUT과 PATCH의 실제 차이점은 무엇입니까? PUT을 사용하여 특정 리소스 아래의 전체 엔터티 를 교체 하는 데 사용할 수있는 곳을 읽었 으므로 PATCH와 같은 속성 집합 대신 전체 엔터티를 보내야합니다. 그러한 경우에 실제적인 사용법은 무엇입니까? 언제 특정 리소스 URI에서 엔티티를 바꾸거나 덮어 쓰고 싶고 왜 그러한 작업이 엔티티 업데이트 / 패치로 간주되지 않습니까? PUT에 대한 실제 사용 사례는 컬렉션에 PUT을 발행하는 것입니다. 즉 /users전체 컬렉션을 교체하는 것입니다. PATCH가 도입 된 후에 특정 엔티티에 PUT을 발행하는 것은 의미가 없습니다. 내가 잘못?

1
a) 2612가 아닌 RFC 2616입니다. b) RFC 2616이 폐기되었습니다. PUT의 현재 사양은 greenbytes.de/tech/webdav/rfc7231.html#PUT입니다 . c) 질문이 없습니다. PUT이 컬렉션뿐만 아니라 모든 리소스를 대체하는 데 사용될 수 있다는 것은 분명하지 않습니다 .d) PATCH가 소개되기 전에 사람들이 일반적으로 POST를 사용했습니다 .e) 마침내 특정 패치 요청 (패치 형식에 따라 다름) dem 등 증일 있습니다. 그것은 일반적으로 그렇지 않다는 것입니다.
Julian Reschke

도움이된다면 나는 PUT의 대 패치에 대한 기사 작성했습니다 eq8.eu/blogs/36-patch-vs-put-and-the-patch-json-syntax-war
equivalent8

5
단순 : POST는 컬렉션에 항목을 만듭니다. PUT은 항목을 대체합니다. PATCH는 항목을 수정합니다. POST 할 때 새 항목의 URL이 계산되어 응답으로 반환되는 반면 PUT 및 PATCH는 요청에 URL이 필요합니다. 권리?
Tom Russell

이 게시물은 유용 할 수 있습니다 : POST vs PUT vs PATCH : mscharhag.com/api-design/http-post-put-patch
micha

답변:


943

참고 : REST에 대해 처음 읽었을 때, dem 등성은 혼란스러워하는 개념이었습니다. 추가 의견 (및 Jason Hoetger 's answer )이 보여 주었 듯이 여전히 원래의 대답에서 제대로 이해하지 못했습니다 . 한동안, 나는 Jason을 효과적으로 표절하는 것을 피하기 위해이 답변을 광범위하게 업데이트하는 것을 거부했지만, 나는 (의견에) 질문을 받았기 때문에 지금 편집하고 있습니다.

내 대답을 읽은 후에도이 질문에 대한 Jason Hoetger의 훌륭한 답변 을 읽을 것을 제안 하며 단순히 Jason을 훔치지 않고 더 나은 답변을 얻으려고 노력할 것입니다.

PUT이 dem 등원 인 이유는 무엇입니까?

RFC 2616 인용에서 언급했듯이 PUT은 dem 등원으로 간주됩니다. 리소스를 PUT하면 다음 두 가지 가정이 적용됩니다.

  1. 컬렉션이 아닌 엔터티를 참조하고 있습니다.

  2. 공급중인 법인이 완료되었습니다 ( 전체 법인).

예 중 하나를 봅시다.

{ "username": "skwee357", "email": "skwee357@domain.com" }

/users제안한대로이 문서를에 게시하면 다음과 같은 엔티티를 다시 얻을 수 있습니다.

## /users/1

{
    "username": "skwee357",
    "email": "skwee357@domain.com"
}

나중에이 엔티티를 수정하려면 PUT과 PATCH 중에서 선택하십시오. PUT은 다음과 같습니다.

PUT /users/1
{
    "username": "skwee357",
    "email": "skwee357@gmail.com"       // new email address
}

PATCH를 사용하여 동일한 작업을 수행 할 수 있습니다. 다음과 같이 보일 수 있습니다.

PATCH /users/1
{
    "email": "skwee357@gmail.com"       // new email address
}

이 둘 사이의 차이점을 바로 알 수 있습니다. PUT에는이 사용자의 모든 매개 변수가 포함되었지만 PATCH에는 수정중인 매개 변수 만 포함되었습니다 ( email).

PUT을 사용하는 경우 완전한 엔티티를 전송하는 것으로 가정하고 해당 완전한 엔티티 해당 URI의 기존 엔티티를 대체 합니다. 위의 예에서 PUT과 PATCH는 동일한 목표를 달성합니다. 둘 다이 사용자의 전자 메일 주소를 변경합니다. 그러나 PUT은 전체 엔터티를 교체하여 처리하지만 PATCH는 제공된 필드 만 업데이트하고 다른 필드는 그대로 둡니다.

PUT 요청에는 전체 엔터티가 포함되므로 동일한 요청을 반복적으로 발행하면 항상 동일한 결과를 가져야합니다 (보낸 데이터는 이제 엔터티의 전체 데이터 임). 따라서 PUT은 dem 등원입니다.

잘못된 PUT 사용

PUT 요청에서 위의 PATCH 데이터를 사용하면 어떻게됩니까?

GET /users/1
{
    "username": "skwee357",
    "email": "skwee357@domain.com"
}
PUT /users/1
{
    "email": "skwee357@gmail.com"       // new email address
}

GET /users/1
{
    "email": "skwee357@gmail.com"      // new email address... and nothing else!
}

(이 질문의 목적 상 서버에는 특정 필수 필드가 없으며 이것이 가능할 것이라고 가정합니다. 실제로는 그렇지 않을 수도 있습니다.)

우리는 PUT을 사용했지만 공급 만 했으므로 email이제이 엔티티에서 유일한 것입니다. 이로 인해 데이터가 손실되었습니다.

이 예제는 설명을위한 것입니다. 실제로이 작업을 수행하지 마십시오. 이 PUT 요청은 기술적으로 dem 등 적이지만 끔찍한 아이디어가 아니라는 의미는 아닙니다.

패치는 어떻게 dem 등식이 될 수 있습니까?

위의 예에서 PATCH dem 등원 이었습니다 . 변경했지만 동일한 변경을 계속 반복하면 항상 동일한 결과가 나타납니다. 전자 메일 주소를 새 값으로 변경했습니다.

GET /users/1
{
    "username": "skwee357",
    "email": "skwee357@domain.com"
}
PATCH /users/1
{
    "email": "skwee357@gmail.com"       // new email address
}

GET /users/1
{
    "username": "skwee357",
    "email": "skwee357@gmail.com"       // email address was changed
}
PATCH /users/1
{
    "email": "skwee357@gmail.com"       // new email address... again
}

GET /users/1
{
    "username": "skwee357",
    "email": "skwee357@gmail.com"       // nothing changed since last GET
}

정확성을 위해 고정 된 나의 원래 예

나는 원래 비 등가성을 보여주고 있다고 생각한 예를 가지고 있었지만 오도하고 잘못되었습니다. 예제를 유지하되, 다른 것을 설명하기 위해 사용할 것입니다. 같은 엔티티에 대해 여러 개의 PATCH 문서가 다른 속성을 수정하더라도 PATCH가 비등 전성이되지는 않습니다.

과거에 사용자가 추가되었다고 가정 해 봅시다. 이것은 당신이 시작한 상태입니다.

{
  "id": 1,
  "name": "Sam Kwee",
  "email": "skwee357@olddomain.com",
  "address": "123 Mockingbird Lane",
  "city": "New York",
  "state": "NY",
  "zip": "10001"
}

PATCH 후에 수정 된 엔티티가 있습니다.

PATCH /users/1
{"email": "skwee357@newdomain.com"}

{
  "id": 1,
  "name": "Sam Kwee",
  "email": "skwee357@newdomain.com",    // the email changed, yay!
  "address": "123 Mockingbird Lane",
  "city": "New York",
  "state": "NY",
  "zip": "10001"
}

그런 다음 PATCH를 반복해서 적용하면 동일한 결과가 계속 나타납니다. 전자 메일이 새로운 값으로 변경되었습니다. A는 들어오고 A는 나옵니다. 그러므로 이것은 dem 등입니다.

한 시간 후에 커피를 마시고 휴식을 취한 후 다른 사람이 자신의 패치를 가지고옵니다. 우체국에서 약간의 변화가 있었을 것 같습니다.

PATCH /users/1
{"zip": "12345"}

{
  "id": 1,
  "name": "Sam Kwee",
  "email": "skwee357@newdomain.com",  // still the new email you set
  "address": "123 Mockingbird Lane",
  "city": "New York",
  "state": "NY",
  "zip": "12345"                      // and this change as well
}

이 우체국의 PATCH는 전자 우편과 관련이 없으며 우편 번호 만 반복 적용되는 경우 우편 번호 만 새로운 값으로 설정됩니다. A는 들어오고 A는 나옵니다. 따라서 이것은 또한 dem 등합니다.

다음 날, PATCH를 다시 ​​보내기로 결정했습니다.

PATCH /users/1
{"email": "skwee357@newdomain.com"}

{
  "id": 1,
  "name": "Sam Kwee",
  "email": "skwee357@newdomain.com",
  "address": "123 Mockingbird Lane",
  "city": "New York",
  "state": "NY",
  "zip": "12345"
}

패치는 어제와 동일한 효과를 나타냅니다. 전자 메일 주소를 설정합니다. A가 들어 왔고, A가 나왔으므로 이것 또한 dem 등합니다.

원래 답변에서 내가 잘못한 것

중요한 구별을 원합니다 (원래 답변에서 잘못된 점이 있음). 많은 서버가 수정 사항 (있는 경우)과 함께 새 엔티티 상태를 다시 보내 REST 요청에 응답합니다. 따라서이 응답을 다시 받으면 우편 번호가 지난 번에받은 것이 아니기 때문에 어제받은 것과 다릅니다 . 그러나 귀하의 요청은 우편 번호와 관련이 없으며 전자 메일과 관련이 있습니다. 따라서 PATCH 문서는 여전히 dem 등원입니다. PATCH로 보낸 이메일은 이제 엔티티의 이메일 주소입니다.

그렇다면 PATCH가 dem 등성이 아닌 때는 언제입니까?

이 질문을 완전히 처리하려면 Jason Hoetger의 답변 을 다시 참조하십시오 . 솔직히 말해서이 부분에 대해 그가 이미 가지고있는 것보다 더 잘 대답 할 수는 없다고 생각하기 때문입니다.


2
이 문장은 옳지 않다 : "하지만 dem 등하 다 : A가 들어올 때마다 B는 항상 나간다". 예를 들어, GET /users/1우체국에서 우편 번호를 업데이트하기 전에 방문한 후 다시 GET /users/1우체국 업데이트 후 동일한 요청을하면 두 가지 다른 응답 (우편 우편 번호)이 표시됩니다. 동일한 "A"(GET 요청)가 진행되고 있지만 결과가 다릅니다. 그러나 GET은 여전히 ​​dem 등합니다.
Jason Hoetger

@JasonHoetger GET은 안전하지만 (변경이 없을 것으로 추정 됨) 항상 always 등하지는 않습니다. 차이가 있습니다. RFC 2616 초를 참조하십시오 . 9.1 .
Dan Lowe

1
@ DanLowe : GET은 확실히 dem 등을 보장합니다. RFC 2616의 섹션 9.1.2와 업데이트 된 사양 인 RFC 7231 섹션 4.2.2 에서 "이 사양에 의해 정의 된 요청 방법 중 PUT, DELETE 및 안전한 요청 방법은 pot 등원" 이라고 정확하게 기술하고있다 . dem 등성이 단지 "동일한 요청을 할 때마다 동일한 응답을 받는다"는 의미는 아닙니다. 7231 4.2.2는 다음과 같이 말합니다. " 응답이 다를 수 있지만 원래 요청이 성공하더라도 요청을 반복하면 의도 한 효과가 동일 합니다. "
Jason Hoetger

1
@JasonHoetger 나는 그것을 인정할 것이다. 그러나 나는 PUT과 PATCH를 논의하고 결코 GET을 언급하지 않은이 답변과 어떤 관계가 있는지 보지 못한다.
Dan Lowe

1
아, @JasonHoetger의 의견은 그것을 밝혔습니다. 응답이 아닌 여러 dem 등식 메소드 요청의 결과 상태 만 동일하면됩니다.
Tom Russell

329

Dan Lowe의 탁월한 답변은 PUT과 PATCH의 차이점에 대한 OP의 질문에 매우 철저하게 답변했지만 PATCH가 dem 등성이 아닌 이유에 대한 답변은 정확하지 않습니다.

PATCH가 dem 등성이 아닌 이유를 보여주기 위해, dem 등가의 정의 ( Wikipedia에서 ) 로 시작하는 것이 도움이됩니다 .

idempotent라는 용어는 한 번 또는 여러 번 실행될 경우 동일한 결과를 생성하는 작업을 설명하기 위해보다 포괄적으로 사용됩니다. [...] idempotent 함수는 f (f (x)) = f (x) 속성을 갖는 함수입니다. 모든 값 x.

보다 접근하기 쉬운 언어에서 dem 등원 (Idempotent) PATCH는 다음과 같이 정의 할 수 있습니다. 패치 문서로 자원을 패치 한 후 동일한 패치 문서로 동일한 자원에 대한 모든 후속 PATCH 호출은 자원을 변경하지 않습니다.

반대로, 비등 전성 (non-idempotent) 연산은 f (f (x))! = f (x) 인 PATCH의 경우 다음과 같이 표현할 수 있습니다. 패치 문서로 리소스를 패치 한 후 후속 PATCH는 동일한 패치 문서 리소스를 변경합니다.

비등 전성 PATCH를 설명하기 위해 / users 자원이 있고 호출이 GET /users현재 사용자 목록을 리턴 한다고 가정하십시오 .

[{ "id": 1, "username": "firstuser", "email": "firstuser@example.org" }]

OP의 예에서와 같이 PATCHing / users / {id} 대신 서버가 PATCHing / users를 허용한다고 가정하십시오. 이 패치 요청을 발행하겠습니다 :

PATCH /users
[{ "op": "add", "username": "newuser", "email": "newuser@example.org" }]

패치 문서는 서버가 사용자 newuser목록에 호출 된 새 사용자를 추가하도록 지시합니다 . 이것을 처음 호출하면 다음 GET /users을 반환합니다.

[{ "id": 1, "username": "firstuser", "email": "firstuser@example.org" },
 { "id": 2, "username": "newuser", "email": "newuser@example.org" }]

위와 정확히 동일한 PATCH 요청을 발행하면 어떻게됩니까? (이 예제를 위해 / users 자원이 중복 된 사용자 이름을 허용한다고 가정합니다.) "op"는 "add"이므로 새 사용자가 목록에 추가되고 후속 GET /users결과가 리턴됩니다.

[{ "id": 1, "username": "firstuser", "email": "firstuser@example.org" },
 { "id": 2, "username": "newuser", "email": "newuser@example.org" },
 { "id": 3, "username": "newuser", "email": "newuser@example.org" }]

정확히 동일한 엔드 포인트 에 대해 동일한 PATCH를 발행했지만 / users 자원이 다시 변경되었습니다 . PATCH가 f (x)이면 f (f (x))는 f (x)와 같지 않으므로이 특정 PATCH는 dem 등원이 아닙니다 .

PATCH가 dem 등원을 보장 하지는 않지만 PATCH 스펙에는 특정 서버에서 dem 등원을 모두 PATCH 조작하지 못하게하는 내용이 없습니다. RFC 5789는 dem 등원 PATCH 요청의 이점을 기대합니다.

PATCH 요청은 dem 등원 방식으로 발행 될 수 있으며, 이는 동일한 시간 프레임에서 동일한 자원에 대한 두 PATCH 요청 간의 충돌로 인한 나쁜 결과를 방지하는 데 도움이됩니다.

Dan의 예에서, 그의 PATCH 조작은 실제로 dem 등원입니다. 이 예에서 / users / 1 엔티티는 PATCH 요청간에 변경되었지만 PATCH 요청 때문에 변경되지 않았습니다 . 실제로 우편 번호가 변경 되는 우체국의 다른 패치 문서였습니다. 우체국의 다른 PATCH는 다른 작업입니다. PATCH가 f (x)이면 우체국의 PATCH는 g (x)입니다. dem 등식은 다음과 같이 진술 f(f(f(x))) = f(x)하지만 보증하지는 않는다 f(g(f(x))).


11
서버가에서 PUT 발급을 허용한다고 가정하면 PUT도 /users비등 전성으로 만듭니다. 이 모든 것은 서버가 요청을 처리하도록 설계된 방식입니다.
Uzair Sajid 2012 년

13
따라서 PATCH 작업으로 만 API를 작성할 수 있습니다. 그러면 http VERBS를 사용하여 리소스에 대한 CRUD 작업을 수행하는 REST 원칙은 무엇입니까? 여기서 PATCH 경계선 신사들을 지나치게 복잡하게하지 않습니까?
bohr

6
PUT이 컬렉션 (예 :)에서 구현 /users되면 모든 PUT 요청이 해당 컬렉션의 내용을 대체해야합니다. 따라서 PUT /users은 사용자 모음을 예상하고 나머지는 모두 삭제해야합니다. 이것은 dem 등이다. / users 엔드 포인트에서 그러한 작업을 수행하지는 않을 것입니다. 그러나 /users/1/emails컬렉션과 같은 것이있을 수 있으며 전체 컬렉션을 새 컬렉션으로 교체하는 것이 완벽하게 유효 할 수 있습니다.
Vectorjohn

5
이 답변은 dem 등의 좋은 예를 제공하지만 전형적인 REST 시나리오에서 물이 흐릴 수 있다고 생각합니다. 이 경우 op특정 서버 측 로직을 트리거 하는 추가 조치 가 포함 된 PATCH 요청이 있습니다. 이를 위해서는 서버와 클라이언트가 op필드가 서버 측 워크 플로우를 트리거 하기 위해 전달할 특정 값을 알고 있어야 합니다. 보다 간단한 REST 시나리오에서이 유형의 op기능은 좋지 않으며 HTTP 동사를 통해 직접 처리해야합니다.
ivandov

7
나는 컬렉션에 대해 PATCH, POST 및 DELETE 만 발행하는 것을 고려하지 않을 것입니다. 이거 진짜 끝났어? 그러므로 PATCH를 모든 실제적인 목적으로 dem 등으로 간주 할 수 있습니까?
Tom Russell

72

나는 이것에 대해서도 궁금했고 흥미로운 기사를 발견했습니다. 귀하의 질문에 최대한 답변하지는 못할 수도 있지만 최소한 추가 정보를 제공합니다.

http://restful-api-design.readthedocs.org/en/latest/methods.html

HTTP RFC는 PUT이 요청 엔티티로서 완전히 새로운 자원 표현을 가져야한다고 지정합니다. 예를 들어 특정 속성 만 제공되는 경우 해당 속성을 제거해야합니다 (즉, null로 설정).

그렇다면 PUT은 전체 객체를 보내야합니다. 예를 들어

/users/1
PUT {id: 1, username: 'skwee357', email: 'newemail@domain.com'}

이것은 효과적으로 이메일을 업데이트합니다. PUT이 너무 효과적이지 않은 이유는 실제로 하나의 필드를 수정하고 사용자 이름을 포함하는 것이 쓸모가 없기 때문입니다. 다음 예는 차이점을 보여줍니다.

/users/1
PUT {id: 1, email: 'newemail@domain.com'}

이제 PUT이 사양에 따라 설계된 경우 PUT은 사용자 이름을 null로 설정하고 다음을 다시 얻습니다.

{id: 1, username: null, email: 'newemail@domain.com'}

PATCH를 사용하면 지정한 필드 만 업데이트하고 나머지 예제는 그대로 둡니다.

PATCH에 대한 다음 테이크는 이전에 본 적이없는 것과 약간 다릅니다.

http://williamdurand.fr/2014/02/14/please-do-not-patch-like-an-idiot/

PUT 요청과 PATCH 요청의 차이점은 서버가 동봉 된 엔터티를 처리하여 Request-URI로 식별되는 리소스를 수정하는 방식에 반영됩니다. PUT 요청에서 동봉 된 엔터티는 원본 서버에 저장된 수정 된 버전의 리소스로 간주되며 클라이언트는 저장된 버전의 교체를 요청합니다. 그러나 PATCH를 사용하면 동봉 된 엔터티에는 현재 원본 서버에있는 리소스를 수정하여 새 버전을 생성하는 방법을 설명하는 지침 세트가 포함됩니다. PATCH 메소드는 Request-URI로 식별 된 자원에 영향을 미치며 다른 자원에도 부작용이있을 수 있습니다. 즉, PATCH의 적용에 의해 새로운 자원이 생성되거나 기존의 자원이 수정 될 수있다.

PATCH /users/123

[
    { "op": "replace", "path": "/email", "value": "new.email@example.org" }
]

PATCH를 필드를 업데이트하는 방법으로 취급하고 있습니다. 따라서 부분 객체를 전송하는 대신 작업을 전송합니다. 즉, 이메일을 가치로 교체하십시오.

기사는 이것으로 끝납니다.

Fielding의 논문은 부분적으로 리소스를 수정하는 방법을 정의하지 않기 때문에 PATCH는 진정으로 REST API를 위해 설계된 것은 아닙니다. 그러나 Roy Fielding은 PATCH는 부분적인 PUT이 결코 RESTful하지 않기 때문에 초기 HTTP / 1.1 제안을 위해 만들어진 것이라고 말했다. 완전한 표현을 전송하지는 않지만 REST는 표현을 완성 할 필요가 없습니다.

이제는 많은 주석가가 지적한 것처럼 기사에 특히 동의하는지 모르겠습니다. 부분 표현을 전송하면 변경 사항을 쉽게 설명 할 수 있습니다.

나에게 PATCH를 사용하는 것에 혼란스러워합니다. 대부분의 경우, PUT을 PATCH로 취급 할 것입니다. 지금까지 내가 목격 한 유일한 차이점은 PUT이 결 측값을 null로 설정해야한다는 것입니다. 그것을하는 '가장 올바른'방법은 아니지만 행운을 빌어 코딩 완벽합니다.


7
William Durand의 기사 (및 rfc 6902)에는 "op"가 "add"인 예가 있습니다. 이것은 분명히 dem 등성이 아닙니다.
Johannes Brodwall

2
또는 RFC 7396 병합 패치를 더 쉽게 사용하고 대신 패치 JSON 빌드를 피할 수 있습니다.
Piotr Kula

nosql 테이블의 경우, nosql에는 열이 없기 때문에 patch와 put의 차이점이 중요합니다.
stackdave

18

PUT과 PATCH의 차이점은 다음과 같습니다.

  1. PUT은 dem 등원이어야합니다. 이를 달성하기 위해서는 전체 본문을 요청 본문에 넣어야합니다.
  2. PATCH는 비등 전성일 수 있습니다. 그것은 당신이 묘사 한 경우와 같이 어떤 경우에는 dem 등 수 있습니다.

PATCH는 서버에게 리소스를 수정하는 방법을 알려주기 위해 "패치 언어"가 필요합니다. 호출자와 서버는 "add", "replace", "delete"와 같은 일부 "작업"을 정의해야합니다. 예를 들면 다음과 같습니다.

GET /contacts/1
{
  "id": 1,
  "name": "Sam Kwee",
  "email": "skwee357@olddomain.com",
  "state": "NY",
  "zip": "10001"
}

PATCH /contacts/1
{
 [{"operation": "add", "field": "address", "value": "123 main street"},
  {"operation": "replace", "field": "email", "value": "abc@myemail.com"},
  {"operation": "delete", "field": "zip"}]
}

GET /contacts/1
{
  "id": 1,
  "name": "Sam Kwee",
  "email": "abc@myemail.com",
  "state": "NY",
  "address": "123 main street",
}

패치 언어는 명시적인 "작업"필드를 사용하는 대신 다음과 같은 규칙을 정의하여 암시 적으로 만들 수 있습니다.

PATCH 요청 본문에서 :

  1. 필드가 존재한다는 것은 해당 필드를 "대체"또는 "추가"한다는 의미입니다.
  2. 필드 값이 널인 경우 해당 필드를 삭제함을 의미합니다.

위의 규칙을 사용하면 예제의 PATCH는 다음 형식을 취할 수 있습니다.

PATCH /contacts/1
{
  "address": "123 main street",
  "email": "abc@myemail.com",
  "zip":
}

더 간결하고 사용자 친화적으로 보입니다. 그러나 사용자는 기본 규칙을 알고 있어야합니다.

위에서 언급 한 작업으로 PATCH는 여전히 dem 등합니다. 그러나 "증가"또는 "추가"와 같은 연산을 정의하면 더 이상 dem 등성이 아니라는 것을 쉽게 알 수 있습니다.


7

TLDR-바보 다운 버전

PUT => 기존 자원에 대한 모든 새 속성을 설정하십시오.

PATCH => 기존 리소스를 부분적으로 업데이트합니다 (모든 속성이 필요한 것은 아님).


3

이전 의견에서 이미 인용 한 RFC 7231 섹션 4.2.2를 인용하고보다 자세히 인용하겠습니다 .

요청 방법은 해당 방법으로 여러 동일한 요청이있는 서버에서 의도 한 효과가 단일 요청에 대한 효과와 동일하면 "등전위"로 간주됩니다. 이 사양에서 정의한 요청 방법 중에서 PUT, DELETE 및 안전한 요청 방법이 dem 등원입니다.

(...)

클라이언트가 서버의 응답을 읽기 전에 통신 실패가 발생하면 요청이 자동으로 반복 될 수 있기 때문에 dem 등원 한 방법이 구별됩니다. 예를 들어, 클라이언트가 PUT 요청을 보내고 응답이 수신되기 전에 기본 연결이 닫히면 클라이언트는 새 연결을 설정하고 dem 등원 (Idempotent) 요청을 다시 시도 할 수 있습니다. 응답이 다를 수 있지만 원래 요청이 성공하더라도 요청을 반복하면 의도 한 효과가 동일하다는 것을 알고 있습니다.

따라서 dem 등식 방법을 반복해서 요청한 후에 "동일"해야하는 것은 무엇입니까? 서버 상태 나 서버 응답이 아니라 의도 한 효과 . 특히,이 방법은 "클라이언트의 관점에서"dem 등원이어야합니다. 이제이 관점은 내가 표절하고 싶지 않은 Dan Lowe 's answer 의 마지막 예가 실제로 PATCH 요청이 비 등장 적 일 수 있음을 보여줍니다. Jason Hoetger의 답변 ).

실제로, 첫 번째 고객을 위해 가능한 한 명확한 의도 를 만들어서 예제를 약간 더 정확하게 만들어 봅시다 . 이 고객이 프로젝트를 가진 사용자 목록을 통해 이메일 우편 번호 를 확인한다고 가정 해 보겠습니다 . 그는 사용자 1부터 시작하여 우편 번호는 맞지만 전자 메일은 잘못되었음을 알 수 있습니다. 그는 완전히 합법적 인 PATCH 요청으로이 문제를 해결하기로 결정하고

PATCH /users/1
{"email": "skwee357@newdomain.com"}

이것이 유일한 수정이기 때문입니다. 이제 일부 네트워크 문제로 인해 요청이 실패하고 몇 시간 후에 자동으로 다시 제출됩니다. 한편, 다른 클라이언트가 사용자 1의 우편 번호를 잘못 수정했습니다. 그런 다음, 동일한 PATCH 요청을 두 번 보내는 것은 잘못된 우편 번호로 인해 클라이언트 의 의도 된 효과 를 달성하지 못합니다 . 따라서이 방법은 RFC의 관점에서 dem 등하 지 않습니다.

대신 클라이언트가 PUT 요청을 사용하여 전자 메일을 수정하고 전자 메일과 함께 사용자 1의 모든 속성을 서버에 보내는 경우 나중에 요청을 다시 보내야하고 사용자 1이 수정 된 경우에도 의도 한 효과가 나타납니다. 한편 --- 두 번째 PUT 요청은 첫 번째 요청 이후의 모든 변경 사항을 덮어 쓰기 때문입니다.


2

겸손한 견해로는 dem 등식은 다음을 의미합니다.

  • 놓다:

경쟁 리소스 정의를 보내므로 결과 리소스 상태는 PUT 매개 변수에 의해 정의 된 것과 정확히 같습니다. 매번 동일한 PUT 매개 변수로 리소스를 업데이트 할 때마다 결과 상태는 정확히 같습니다.

  • 반점:

리소스 정의의 일부만 보냈으므로 다른 사용자가 그 동안이 리소스의 OTHER 매개 변수를 업데이트하고있을 수 있습니다. 결과적으로 매개 변수와 값이 동일한 연속 패치는 다른 자원 상태로 나타날 수 있습니다. 예를 들어 :

다음과 같이 정의 된 객체를 가정하십시오.

자동차 :-색상 : 검정,-유형 : 세단 형 자동차, 좌석 : 5

나는 그것을 패치 :

{색상 : '빨간색'}

결과 개체는 다음과 같습니다.

자동차 :-색상 : 빨간색, 유형 : 세단 형 자동차, 좌석 : 5

그런 다음 다른 사용자가이 자동차를 다음과 같이 패치합니다.

{유형 : '해치백'}

결과 객체는 다음과 같습니다.

자동차 :-색상 : 빨간색, 유형 : 해치백, 좌석 : 5

이제이 객체를 다시 패치하면 :

{색상 : '빨간색'}

결과 객체는 다음과 같습니다.

자동차 :-색상 : 빨간색, 유형 : 해치백, 좌석 : 5

내가 이전에 얻은 것과 다른 점은 무엇입니까!

그렇기 때문에 PUT이 dem 등원 인 반면 PATCH는 dem 등원이 아닙니다.


1

dem 등원에 대한 논의를 마치기 위해 REST 컨텍스트에서 dem 등원을 두 가지 방법으로 정의 할 수 있습니다. 먼저 몇 가지를 공식화합시다.

자원 의 공역 문자열의 클래스로되는 함수이다. 다시 말해, 리소스는의 String × Any모든 부분 이 고유 한의 하위 집합입니다 . resources 클래스를 호출하자 Res.

자원에 대한 REST 조작은 함수 f(x: Res, y: Res): Res입니다. REST 조작의 두 가지 예는 다음과 같습니다.

  • PUT(x: Res, y: Res): Res = x,
  • PATCH(x: Res, y: Res): Res처럼 작동합니다 PATCH({a: 2}, {a: 1, b: 3}) == {a: 2, b: 3}.

(이 정의는 특히 PUTand POST에 대해 논쟁하도록 고안되었으며 , 예를 들어 영속성에 신경 쓰지 않기 때문에 GETand에 대해서는 의미 POST가 없습니다.)

이제 x: Res(정보 적으로 말하면 카레를 사용하여) 고정 PUT(x: Res)하고 PATCH(x: Res)유형의 일 변량 함수입니다 Res → Res.

  1. 함수가 g: Res → Res호출 세계적으로 멱등 때, g ○ g == g어떤을 위해 즉, y: Res, g(g(y)) = g(y).

  2. x: Res자원을 보자 k = x.keys. 함수 g = f(x)left idempotent 라고 불리며 , 각각에 대해 y: Res우리는 가지고 있습니다 g(g(y))|ₖ == g(y)|ₖ. 기본적으로 적용된 키를 보면 결과가 동일해야 함을 의미합니다.

따라서 PATCH(x)전 세계적으로 dem 등성이 아니라 i 등으로 남아 있습니다. 그리고 왼쪽 dem 등식은 여기서 중요한 것입니다. 만약 우리가 리소스의 몇 개의 키를 패치한다면, 우리가 다시 패치하면 그 키가 동일하기를 원하며 나머지 리소스는 신경 쓰지 않습니다.

RFC가 PATCH가 dem 등성이 아니라고 말하면 전역 dem 등성에 대해서도 이야기합니다. 글쎄, 그것은 전 세계적으로 dem 등성이 아니라는 것이 좋다. 그렇지 않으면 부서진 작업이었을 것이다.


이제 Jason Hoetger의 대답 은 PATCH가 dem 등하 지는 않았지만 너무 많은 것들을 깨뜨리고 있음을 보여주기 위해 노력하고 있습니다.

  • 우선 PATCH는 맵 / 사전 / 키-값 객체에서 작동하도록 정의되어 있지만 세트에 사용됩니다.
  • 누군가가 실제로 PATCH를 세트에 적용하려면 다음 t: Set<T> → Map<T, Boolean>과 같이 정의 해야하는 자연스러운 번역이 있습니다 x in A iff t(A)(x) == True. 이 정의를 사용하면 패치가 dem 등원으로 남습니다.
  • 이 예에서는이 변환이 사용되지 않았고 대신 PATCH는 POST처럼 작동합니다. 우선, 왜 객체에 대한 ID가 생성됩니까? 그리고 언제 생성됩니까? 객체가 세트의 요소와 먼저 비교되고 일치하는 객체가 발견되지 않으면 ID가 생성되고 다시 프로그램이 다르게 작동 {id: 1, email: "me@site.com"}해야합니다 (와 일치해야합니다 {email: "me@site.com"}. 그렇지 않으면 프로그램이 항상 중단되고 패치가 가능하지 않습니다 반점). 세트를 점검하기 전에 ID가 생성되면 프로그램이 다시 중단됩니다.

이 예제에서 깨지는 것의 절반을 깨뜨림으로써 PUT가 비등 전성이라는 예를 만들 수 있습니다.

  • 추가 기능생성 된 예는 버전 관리입니다. 단일 객체에 대한 변경 횟수를 기록 할 수 있습니다. 이 경우 PUT은 dem 등성이 아닙니다. PUT /user/12 {email: "me@site.com"}결과 {email: "...", version: 1}는 처음과 {email: "...", version: 2}두 번째입니다.
  • ID를 어지럽히면 객체가 업데이트 될 때마다 새로운 ID를 생성하여 비등 전성 PUT을 생성 할 수 있습니다.

위의 모든 예는 발생할 수있는 자연적인 예입니다.


마지막으로 PATCH는 전역 적으로 global 등하 지 않아야합니다 . 그렇지 않으면 원하는 효과를 얻지 못합니다. 나머지 정보를 건드리지 않고 사용자의 전자 메일 주소를 변경하고 동일한 리소스에 액세스하는 다른 사람의 변경 사항을 덮어 쓰고 싶지 않습니다.


-1

추가해야 할 추가 정보 중 하나는 PATCH 요청이 PUT 요청에 비해 대역폭을 덜 사용한다는 것입니다. 데이터의 일부만 전체 엔터티로 전송되지 않기 때문입니다. 따라서 (1-3 레코드)와 같은 특정 레코드의 업데이트에는 PATCH 요청을 사용하고 PUT은 더 많은 양의 데이터 업데이트를 요청하십시오. 즉, 너무 많이 생각하거나 너무 걱정하지 마십시오.

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.