REST API 실생활 시나리오에서의 PUT vs 패치 방식 사용
먼저 다음과 같은 정의가 있습니다.
PUT는 섹션 9.6 RFC 2616에 정의되어 있습니다.
PUT 메서드는 지정된 Request-URI 아래에 인클로저드 엔티티를 저장하도록 요구합니다.Request-URI가 이미 존재하는 리소스를 참조하는 경우 인클로저드 엔티티는 오리진서버에 있는 엔티티의 변경 버전으로 간주해야 합니다.Request-URI가 기존 리소스를 가리키지 않고 요청 사용자 에이전트에 의해 URI를 새 리소스로 정의할 수 있는 경우 원본 서버는 해당 URI를 사용하여 리소스를 생성할 수 있습니다.
Patch는 RFC 5789에 정의되어 있습니다.
PATCH 메서드는 Request-URI에 의해 식별된 리소스에 요청 엔티티에 기술된 일련의 변경을 적용하도록 요구합니다.
또한 RFC 2616에 따르면 섹션 9.1.2 PUT는 Idempotent이지만 PATCH는 Idempotent입니다.
이치노에서 POST로 할 때 ★★/users
를 {username: 'skwee357', email: 'skwee357@domain.example'}
할 수 및 합니다(「201」을 합니다)./users/1
및 GET으로 이동합니다./users/1
{id: 1, username: 'skwee357', email: 'skwee357@domain.example'}
.
이제 이메일을 수정하고 싶습니다.의 변경은 「에, 「일련의 변경」으로 패치 ./users/1
"disclosed document"를 사용합니다.제 경우 JSON 문서입니다.{email: 'skwee357@newdomain.example'}
그러면 서버는 200을 반환합니다(권한이 정상이라고 가정). 첫 입니다.
- 패치가 불필요합니다.RFC 2616 및 RFC 5789에 기재되어 있습니다.단, 동일한 패치 요구(새 이메일 사용)를 발행하면 동일한 리소스 상태가 표시됩니다(이 메일은 요청된 값으로 수정됨).PATCH는 왜 쓸모없습니까?
PATCH는 비교적 새로운 동사(2010년 3월에 도입된 RFC)로, 일련의 필드를 「패치」 또는 변경하는 문제를 해결합니다.PATCH가 도입되기 전에는 모든 사용자가 PUT을 사용하여 리소스를 업데이트했습니다.그러나 PATCH가 도입된 후 PUT의 용도가 헷갈립니다.여기서 두 번째(그리고 주요) 질문이 나옵니다.
- PUT과 PATCH의 진정한 차이점은 무엇입니까?PUT는 특정 리소스에서 엔티티 전체를 치환하기 위해 사용될 수 있다는 것을 읽은 적이 있습니다.따라서 (PATCH와 같은 속성 세트가 아니라) 엔티티 전체를 전송해야 합니다.이러한 경우 실제로 어떤 용도가 있을까요?특정 리소스 URI에서 엔티티를 대체/덮어쓰기를 원하는 경우 및 이러한 작업이 엔티티의 업데이트/패치로 간주되지 않는 이유는 무엇입니까?PUT의 유일한 실용적인 활용 사례는 컬렉션에 대한 PUT를 발행하는 것입니다.
/users
전체 컬렉션을 바꿉니다.패치 도입 후 특정 엔티티에 대해 PUT를 발행하는 것은 의미가 없습니다.★★★★★★★★★★★★★★★★★?
메모: 처음에 REST에 대해 읽었을 때, Idempotence는 올바른 것을 얻으려고 하는 혼란스러운 개념이었습니다.더 많은 코멘트(그리고 제이슨 호거의 답변)가 보여주듯, 나는 여전히 원래의 답변에서 제대로 이해하지 못했다.Jason을 효과적으로 표절하지 않기 위해 이 답변을 광범위하게 갱신하는 것을 거부했지만, (댓글에서) 요청받았기 때문에 지금 수정하고 있습니다.
제 답변을 읽은 후, 이 질문에 대한 Jason Hoetger의 훌륭한 답변도 읽어보시길 권합니다.저는 Jason의 답변을 단순히 훔치지 않고 더 나은 답변을 할 수 있도록 노력하겠습니다.
PUT는 왜 무의미합니까?
RFC 2616의 인용에서 설명한 바와 같이 PUT은 아이돌로 간주됩니다.자원을 투입할 때는, 다음의 2개의 전제 조건이 적용됩니다.
컬렉션이 아니라 엔티티를 참조하고 있습니다.
제공하는 엔티티가 완전합니다(엔티티 전체).
예를 들어 보겠습니다.
{ "username": "skwee357", "email": "skwee357@domain.example" }
를 에 /users
, 당신은 수 것입니다.
## /users/1
{
"username": "skwee357",
"email": "skwee357@domain.example"
}
나중에 이 엔티티를 수정하려면 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는 무의미합니다.
잘못된 PUT 사용
위의 패치 데이터를 PUT 요청으로 사용하면 어떻게 됩니까?
GET /users/1
{
"username": "skwee357",
"email": "skwee357@domain.example"
}
PUT /users/1
{
"email": "skwee357@gmail.com" // new email address
}
GET /users/1
{
"email": "skwee357@gmail.com" // new email address... and nothing else!
}
(이 질문의 목적상 서버에는 특정 필수 필드가 없기 때문에 이 작업을 수행할 수 있다고 가정합니다.실제로는 그렇지 않을 수도 있습니다.)
만 제공했기 email
에 데이터가되었습니다.이치노
이 예는 설명을 위해 여기에 나와 있습니다.실제로 이 작업을 수행하지 마십시오(누락된 필드를 삭제하는 것이 목적이 아니라면 물론...).PUT를 사용해야 할 만큼 사용합니다).이 PUT 요청은 기술적으로 무의미하지만 그렇다고 해서 그것이 나쁘고 망가진 아이디어가 아니라는 것을 의미하지는 않습니다.
PATCH는 어떻게 무의미합니까?
위의 예에서는 PATCH가 아이돌 파워였습니다.변경은 했지만 동일한 변경을 반복하면 항상 동일한 결과가 반환됩니다. 즉, 이메일 주소를 새 값으로 변경했습니다.
GET /users/1
{
"username": "skwee357",
"email": "skwee357@domain.example"
}
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 문서가 다른 Atribut을 변경해도 PATCH가 무효가 되지 않습니다.
예를 들어, 어느 시점에서 사용자가 추가되었다고 합시다.이것이 당신이 시작하는 상태입니다.
{
"id": 1,
"name": "Sam Kwee",
"email": "skwee357@olddomain.example",
"address": "123 Mockingbird Lane",
"city": "New York",
"state": "NY",
"zip": "10001"
}
패치 적용 후 엔티티가 변경되었습니다.
PATCH /users/1
{"email": "skwee357@newdomain.example"}
{
"id": 1,
"name": "Sam Kwee",
"email": "skwee357@newdomain.example", // the email changed, yay!
"address": "123 Mockingbird Lane",
"city": "New York",
"state": "NY",
"zip": "10001"
}
그런 다음 패치를 반복적으로 적용하면 동일한 결과가 계속 나타납니다. 즉, 이메일이 새 값으로 변경되었습니다.A가 들어가고 A가 나오므로 이것은 무의미합니다.
1시간 후 커피를 끓이고 휴식을 취한 후 다른 사람이 자신의 패치(PATCH)를 가지고 옵니다.우체국에서 몇 가지 변경을 하고 있는 것 같습니다.
PATCH /users/1
{"zip": "12345"}
{
"id": 1,
"name": "Sam Kwee",
"email": "skwee357@newdomain.example", // still the new email you set
"address": "123 Mockingbird Lane",
"city": "New York",
"state": "NY",
"zip": "12345" // and this change as well
}
우체국으로부터의 이 패치는 이메일과는 관계없기 때문에 우편번호만 반복적으로 적용해도 같은 결과가 됩니다.우편번호는 새로운 값으로 설정됩니다.A가 들어가고 A가 나오므로 이 또한 무의미합니다.
다음 날 패치 재전송을 결정합니다.
PATCH /users/1
{"email": "skwee357@newdomain.example"}
{
"id": 1,
"name": "Sam Kwee",
"email": "skwee357@newdomain.example",
"address": "123 Mockingbird Lane",
"city": "New York",
"state": "NY",
"zip": "12345"
}
패치의 효과는 어제와 같습니다.이메일 주소를 설정합니다.A가 들어갔고 A가 나왔기 때문에 이것도 무의미하다.
내가 원래 대답에서 틀렸던 것
나는 중요한 구별을 하고 싶다.많은 서버가 REST 요구에 응답하여 새로운 엔티티 상태를 (있는 경우) 변경합니다.그래서 이 답변이 돌아왔을 때 어제 받은 우편번호가 아니기 때문에 어제 받은 우편번호가 아니기 때문입니다.그러나 당신의 요청은 우편번호가 아니라 이메일과 관련이 있습니다.따라서 패치 문서는 여전히 유효합니다.패치로 전송한 이메일은 엔티티의 이메일 주소가 됩니다.
그럼 PATCH가 쓸모없는 경우는 언제입니까?
이 질문에 대한 완전한 설명을 위해 Jason Hoetger의 답변을 다시 한 번 참조합니다. 이 답변은 이미 충분히 답변되었습니다.
PUT와 PATCH의 차이에 대한 OP의 질문에 Dan Lowe의 훌륭한 답변은 매우 충실했지만 PATCH가 왜 가치가 없는지에 대한 OP의 답변은 정확하지 않습니다.
PATCH가 왜 무의미하지 않은지를 나타내려면 우선 (Wikipedia에서 참조)의 무의미함의 정의부터 시작해야 합니다.
idempotent라는 용어는 한 번 또는 여러 번 실행할 경우 동일한 결과를 생성하는 작업을 설명하는 데 보다 포괄적으로 사용됩니다. idempotent 함수는 모든 값 x에 대해 f(f(x) = f(x)의 속성을 갖는 함수입니다.
보다 접근하기 쉬운 언어로 Idempotent Patch는 다음과 같이 정의할 수 있습니다.패치 문서를 사용하여 리소스를 패치한 후 동일한 자원에 대한 모든 후속 패치 호출은 리소스를 변경하지 않습니다.
이와 반대로 비잠재적 조작은 f(f(x)!= f(x)가 되는 조작입니다.패치에 대해서는, 패치 문서를 사용해 자원을 패치 한 후에, 같은 패치 문서를 가지는 같은 자원에의 후속의 패치 호출에 의해서 리소스가 변경됩니다.
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" }]
위와 동일한 패치 요구를 발행하면 어떻게 됩니까?(이 예에서는 /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" }]
동일한 엔드포인트에 대해 동일한 패치를 실행했는데도 /users 리소스가 다시 변경되었습니다.패치가 f(x)인 경우 f(f(x)는 f(x)와 동일하지 않기 때문에 이 특정 패치는 무의미합니다.
PATCH가 idempotent를 보증하는 것은 아니지만 PATCH 사양에는 특정 서버의 모든 PATCH 조작을 idempotent로 하는 것을 막는 것은 없습니다.RFC 5789에서는 아이돌 파워 패치 요구의 이점도 상정하고 있습니다.
패치 요구는 아이돌포텐트가 되는 방법으로 발행할 수 있습니다.이를 통해 같은 기간 내에 같은 자원상의 2개의 패치 요구 간에 충돌이 발생하는 것을 방지할 수 있습니다.
Dan의 예에서는 패치 조작은 사실상 무의미합니다.이 예에서는 /users/1 엔티티가 패치 요청 간에 변경되었지만 패치 요청 때문이 아닙니다.우편 번호가 변경된 원인은 실제로는 우체국의 다른 패치 문서입니다.우체국의 다른 패치 조작은 다릅니다.패치가 f(x)일 경우 우체국의 패치는 g(x)입니다.Idempotence는 다음과 같이 기술합니다.f(f(f(x))) = f(x)
,, 에, 에, 에, 에, 습, 습에 대한 보장은 없습니다.f(g(f(x)))
.
TLDR - 덤다운버전
PUT = > 기존 리소스에 대한 모든 새 속성을 설정합니다.
패치 => 기존 리소스를 부분적으로 업데이트합니다(일부 속성이 필요한 것은 아닙니다).
저도 궁금했는데 몇 가지 흥미로운 기사가 있더라고요.당신의 질문에 충분히 답변하지는 못할지 모르지만, 적어도 이것은 더 많은 정보를 제공합니다.
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.example'}
이렇게 하면 이메일이 효과적으로 업데이트됩니다.PUT가 그다지 효과적이지 않을 수 있는 이유는 하나의 필드를 실제로 수정하고 사용자 이름을 포함해도 소용이 없기 때문입니다.다음 예에서는 그 차이를 보여 줍니다.
/users/1
PUT {id: 1, email: 'newemail@domain.example'}
PUT가 사양에 따라 설계되어 있는 경우 PUT에 의해 사용자 이름이 null로 설정되고 다음 정보가 반환됩니다.
{id: 1, username: null, email: 'newemail@domain.example'}
패치 사용 시 지정한 필드만 업데이트하고 나머지는 예시와 같이 그대로 둡니다.
PATCH에 대한 다음 방법은 지금까지 본 적이 없는 것과 조금 다릅니다.
http://williamdurand.fr/2014/02/14/please-do-not-patch-like-an-idiot/
PUT 요구와 PATCH 요구의 차이는 서버가 폐쇄된 엔티티를 처리하여 Request-URI에 의해 식별된 리소스를 변경하는 방식에 반영됩니다.PUT 요청에서 동봉된 엔티티는 원본 서버에 저장된 리소스의 수정된 버전으로 간주되며 클라이언트는 저장된 버전의 교체를 요구합니다.단, PATCH를 사용하는 경우 동봉된 엔티티에는 현재 오리진서버에 있는 자원을 새로운 버전을 작성하기 위해 변경하는 방법이 기재되어 있습니다.PATCH 메서드는 Request-URI에 의해 식별된 리소스에 영향을 줍니다.또, 다른 자원에도 악영향을 미칠 가능성이 있습니다.즉, 패치 적용에 의해 새로운 리소스가 작성되거나 기존 리소스가 변경될 수 있습니다.
PATCH /users/123
[
{ "op": "replace", "path": "/email", "value": "new.email@example.org" }
]
어느 정도 PATCH를 필드를 갱신하는 방법으로 취급하고 있습니다.따라서 부분 개체를 전송하는 대신 작업을 전송합니다. 즉, e-메일을 값으로 바꿉니다.
기사는 이렇게 끝납니다.
PATCH는 진정한 REST API용으로 설계되지 않았습니다.Fielding의 논문에서는 리소스를 부분적으로 변경하는 방법이 정의되어 있지 않기 때문입니다.다만, Roy Fielding 자신은, 부분 PUT는 RESTful이 아니기 때문에, PATCH는 최초의 HTTP/1.1 프로포절용으로 작성된 것이라고 말하고 있습니다.완전한 표현을 전송하는 것은 아니지만 REST에서는 표현을 완료할 필요가 없습니다.
많은 논객들이 지적하듯이 제가 그 기사에 특별히 동의하는지는 모르겠습니다.부분 표현을 전송하는 것은 변경에 대한 설명이 될 수 있습니다.
저는 PATCH를 사용하고 있습니다.PUT는 결측값을 null로 설정해야 한다는 사실만 알 수 있기 때문에 PUT은 패치로서 취급합니다.그것이 '가장 올바른' 방법은 아닐지 모르지만, 완벽한 코드쓰기에 행운을 빈다만 행운을 빈다.
tl;dr 버전
POST: 엔티티를 만드는 데 사용됩니다.
PUT: 저장하려는 엔티티의 전체 표현을 전송해야 하는 기존 엔티티를 업데이트/교체하는 데 사용됩니다.
PATCH: 업데이트해야 할 필드만 전송하는 엔티티를 업데이트하기 위해 사용합니다.
PUT과 PATCH의 차이점은 다음과 같습니다.
- PUT은 유휴해야 합니다.그러기 위해서는 전체 리소스를 요청 본문에 넣어야 합니다.
- PATCH는 아이돌이 아닐 수 있습니다.즉, 설명한 사례와 같이 경우에 따라서는 무의미할 수도 있습니다.
패치에서는 서버에 자원 변경 방법을 지시하기 위해 몇 가지 "패치 언어"가 필요합니다.발신자와 서버는, 「추가」, 「치환」, 「삭제」등의 몇개의 「조작」을 정의할 필요가 있습니다.예를 들어 다음과 같습니다.
GET /contacts/1
{
"id": 1,
"name": "Sam Kwee",
"email": "skwee357@olddomain.example",
"state": "NY",
"zip": "10001"
}
PATCH /contacts/1
{
[{"operation": "add", "field": "address", "value": "123 main street"},
{"operation": "replace", "field": "email", "value": "abc@myemail.example"},
{"operation": "delete", "field": "zip"}]
}
GET /contacts/1
{
"id": 1,
"name": "Sam Kwee",
"email": "abc@myemail.example",
"state": "NY",
"address": "123 main street",
}
패치 언어에서는 명시적인 "operation" 필드를 사용하는 대신 다음과 같은 규칙을 정의함으로써 이를 암묵적으로 만들 수 있습니다.
PATCH 요청 본문:
- 필드의 존재는 해당 필드를 "바꾸기" 또는 "추가"하는 것을 의미합니다.
- 필드 값이 null인 경우 해당 필드를 삭제해야 합니다.
위의 표기법에서는 이 예의 PATCH는 다음 형식을 취할 수 있습니다.
PATCH /contacts/1
{
"address": "123 main street",
"email": "abc@myemail.example",
"zip":
}
어느 쪽이 더 간결하고 사용하기 편해 보입니다.그러나 사용자는 기본 규칙을 인식할 필요가 있습니다.
위에서 설명한 조작으로 PATCH는 아직 유효합니다.그러나 "증가" 또는 "추가"와 같은 작업을 정의하면 더 이상 무의미하지 않음을 쉽게 알 수 있습니다.
제 소견으로는, 게으름뱅이란 다음을 의미합니다.
- 위치:
경쟁 리소스 정의를 전송하므로 결과 리소스 상태는 PUT 매개 변수에 의해 정의된 그대로입니다.매번 동일한 PUT 매개 변수를 사용하여 리소스를 업데이트할 때마다 결과 상태는 완전히 동일합니다.
- 패치:
리소스 정의의 일부만 전송했으므로 다른 사용자가 이 리소스의 OTHER 매개 변수를 업데이트하는 동안 발생할 수 있습니다.따라서 매개 변수와 값이 동일한 패치가 연속되면 리소스 상태가 달라질 수 있습니다.예:
다음과 같이 정의된 개체를 가정합니다.
CAR: - 색상: 검은색, 유형: 세단, 좌석: 5
패치 적용처:
{color: '빨간색'}
결과 객체는 다음과 같습니다.
CAR: - 색상: 빨간색, 유형: 세단, 좌석: 5
그런 다음 일부 다른 사용자가 이 차량에 패치를 적용합니다.
{type: 'backback'}
그 결과 오브젝트는 다음과 같습니다.
CAR: - 색상: 빨간색, 유형: 해치백, 시트: 5
이 오브젝트에 패치를 다시 적용하면 다음과 같습니다.
{color: '빨간색'}
결과 오브젝트는 다음과 같습니다.
CAR: - 색상: 빨간색, 유형: 해치백, 시트: 5
이전과 무엇이 다른가!
이것이 PATCH가 Idempotent가 아닌 반면 PUT는 Idempotent인 이유입니다.
앞서 언급한 RFC 7231 섹션 4.2.2의 인용과 코멘트를 좀 더 자세히 설명하겠습니다.
요구 방식은 동일한 여러 요구의 서버에 대한 의도된 영향이 동일한 단일 요구의 영향과 동일한 경우 "유효한" 것으로 간주됩니다.이 사양에서 정의된 요구 방식 중 PUT, DELETE 및 Safe 요구 방식은 유효합니다.
(...)
Idempotent 메서드는 클라이언트가 서버의 응답을 읽기 전에 통신 장애가 발생했을 때 요청을 자동으로 반복할 수 있기 때문에 구별됩니다.예를 들어 클라이언트가 PUT 요청을 전송하고 응답이 수신되기 전에 기본 연결이 닫히면 클라이언트는 새로운 연결을 확립하고 유휴 요청을 재시도할 수 있습니다.응답은 다를 수 있지만 요청을 반복하면 원래 요청이 성공하더라도 의도한 대로 효과가 있음을 알고 있습니다.
그렇다면, 유휴한 방법을 반복적으로 요청한 후에 "똑같아야 할" 것은 무엇일까요?서버 상태나 서버 응답이 아니라 의도한 효과입니다.특히 메서드는 "클라이언트의 관점에서" 유휴성이 있어야 합니다.이 관점은 Dan Lowe의 답변 중 마지막 예를 제시하지만 여기서 표절하고 싶지는 않습니다.패치 요청은 실제로 무의미할 수 있습니다(Jason Hoetger의 답변보다 더 자연스러운 방법으로).
실제로 첫 번째 클라이언트에 대해 명확한 의도를 제시함으로써 예를 조금 더 정확하게 만들어 보겠습니다.이 클라이언트가 프로젝트의 사용자 목록을 검토하여 이메일과 우편 번호를 확인한다고 가정해 보겠습니다.사용자 1부터 시작하여 zip은 맞지만 이메일이 틀렸다는 것을 알게 됩니다.그는 완전히 합법적인 패치 요청을 사용하여 이 문제를 수정하기로 결정하고
PATCH /users/1
{"email": "skwee357@newdomain.example"}
이게 유일한 수정사항이기 때문입니다.이 경우 네트워크 문제로 인해 요구가 실패하고 몇 시간 후에 자동으로 다시 전송됩니다.한편, 다른 클라이언트가 사용자 1의 zip을 (오류적으로) 변경했습니다.그 후, 같은 패치 요구를 재차 송신해도, 클라이언트가 의도한 대로의 효과를 얻을 수 없습니다.그것은 잘못된 zip이 되기 때문입니다.따라서 이 방식은 RFC의 의미에서는 의미가 없습니다.
클라이언트가 PUT 요구를 사용하여 전자 메일을 수정하고 사용자 1의 모든 속성을 전자 메일과 함께 서버로 전송하면 요청이 나중에 다시 전송되고 그 사이에 사용자 1이 수정되어도 원하는 효과가 발생합니다.두 번째 PUT 요청은 첫 번째 요청 이후의 모든 변경 사항을 덮어씁니다.
잠재력에 대한 당신의 질문을 생각하면 주제에서 조금 벗어난 것 같습니다만, 진화론을 고려해 주셨으면 합니다.
다음 요소가 있다고 가정합니다.
{
"username": "skwee357",
"email": "skwee357@domain.example"
}
PUT을 사용하여 수정하는 경우 개체의 전체 표현을 제공해야 합니다.
PUT /users/1
{
"username": "skwee357",
"email": "skwee357@newdomain.example"
}
스키마를 를 추가합니다.phone
:
PUT /users/1
{
"username": "skwee357",
"email": "skwee357@newdomain.example",
"phone": "123-456-7890"
}
PUT을 하면 PUT이 됩니다.phone
무효로 합니다.이러한 부작용을 방지하려면 스키마를 업데이트할 때마다 요소를 수정하는 모든 구성요소를 업데이트해야 합니다.
PATCH는 지정된 필드만 업데이트하기 때문에 PATCH를 사용하면 이 문제가 발생하지 않습니다.따라서 PATCH를 사용하여 요소를 수정해야 합니다(실제로 중요하지 않은지 여부).그것은 실제 경험의 귀환이다.
다른 모든 사용자가 PUT vs PATCH에 응답했습니다.저는 원래 질문의 제목 중 "...REST API 실생활 시나리오에서"라는 부분에 대한 답변을 드리려고 했습니다.실제로 RESTful 서버가 있는 인터넷 어플리케이션과 고객 테이블이 넓은 관계형 데이터베이스(약 40열)에서 이러한 현상이 발생했습니다.실수로 PUT을 사용했는데 SQL Update 명령어라고 생각하고 모든 컬럼을 작성하지 않았습니다.문제: 1) 일부 컬럼은 옵션(공백이 유효한 답변), 2) 많은 컬럼은 거의 변경되지 않았습니다. 3) 마지막 구매일의 타임스탬프 등 사용자가 변경할 수 없는 컬럼이 있습니다.또한 1컬럼은 자유 형식의 텍스트 "댓글" 컬럼으로, 배우자 등의 고객 서비스에 대한 코멘트로 부지런히 채워져 있습니다.또는 보통 주문 5) 인터넷 앱을 사용하고 있었는데 패킷 사이즈가 걱정되었습니다.
PUT의 단점은 대량의 정보 패킷(몇 가지 변경 사항만 있어도 Comments 열 전체를 포함한 모든 열)과 2명 이상의 사용자가 같은 고객을 동시에 편집하는 다중 사용자 문제(따라서 Update를 누르면 성공)를 강제로 전송해야 한다는 것입니다.PATCH의 단점은 변경된 부분을 표시/화면 측에서 추적해야 하며 변경된 부분만 전송할 수 있는 지능이 있어야 한다는 것입니다.패치의 다중 사용자 문제는 동일한 고객의 동일한 열을 편집하는 것으로 제한됩니다.
PUT 방법은 관계형 DB 또는 스토리지와 같은 엔티티와 같은 표 형식으로 데이터를 업데이트하는 데 이상적입니다.사용 사례에 따라 데이터를 부분적으로 업데이트하거나 엔티티 전체를 교체하는 데 사용할 수 있습니다.이것은 항상 무의미할 것이다.
패치 방법을 사용하여 로컬 파일 시스템에 저장되거나 SQL 데이터베이스가 없는 json 또는 xml 형식으로 데이터를 업데이트(또는 재구성)할 수 있습니다.이는 json 객체에 대한 키-값 쌍의 추가/삭제/이동과 같은 요청에서 수행할 액션/조작에 대해 언급함으로써 수행할 수 있습니다.제거 조작을 사용하여 키와 값의 쌍을 삭제할 수 있습니다.또, 중복 요구는, 키가 이전에 삭제되어 아이돌이 아닌 메서드가 되기 때문에, 에러가 발생합니다.json 데이터 패치 적용 요청에 대해서는 RFC 6902를 참조하십시오.
이 문서에는 패치 방법에 대한 자세한 정보가 기재되어 있습니다.
Idempotentity에 대한 논의를 마치기 위해 REST 컨텍스트에서 Idempotentity를 두 가지 방법으로 정의할 수 있다는 점에 유의해야 한다.먼저 몇 가지 사항을 공식화해 보겠습니다.
리소스는 공동 도메인이 문자열 클래스가 되는 함수입니다.즉, 리소스는 다음 중 하나의 서브셋입니다.String × Any
모든 키가 고유합니다. 자원의 자원 요?Res
.
입니다.f(x: Res, y: Res): Res
REST 2는 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}
.
이는 특별히 (에 대해) 되었습니다.PUT
★★★★★★★★★★★★★★★★★」POST
예를 들어, 에 대해서는 별로 의미가 없습니다.GET
★★★★★★★★★★★★★★★★★」POST
지속성에는 관심이 없기 때문에).
,, 정으써써 now를 x: Res
(카레를 사용해서), (카레잉을 사용해서), (카레잉을 사용해서), (카레잉을 사용해서),PUT(x: Res)
★★★★★★★★★★★★★★★★★」PATCH(x: Res)
는 일변량 입니다.Res → Res
.
a
g: Res → Res
global idempotent라고 불리는 경우g ○ g == g
임의의 )y: Res
,g(g(y)) = g(y)
.let let 렛츠고
x: Res
및k = x.keys
. 수수g = f(x)
왼쪽 아이돌 퍼텐트라고 불리며, 각각에 대해y: Res
있습니다.g(g(y))|ₖ == g(y)|ₖ
적용되는 키를 보면 기본적으로 결과는 같아야 한다는 것을 의미합니다.
so,는,PATCH(x)
idempotent는 아니지만 는 idempotent로 남습니다.여기서 중요한 것은 왼쪽의 유휴성입니다.리소스의 몇 개의 키에 패치를 적용하면 다시 패치를 적용해도 동일한 키가 유지되도록 하고 나머지 자원에 대해서는 신경 쓰지 않습니다.
RFC는 PATCH가 아이돌이 아니라고 할 때 글로벌아이덴티시에 대해서 말하고 있습니다음, 세계적으로 쓸모없는 것이 아니라서 다행이네요. 그렇지 않았다면 수술이 중단되었을 거예요.
Jason Hoetger의 답변은 PATCH가 유휴 상태로 남아 있지 않다는 것을 보여주려 하고 있지만, PATCH가 너무 많은 것을 깨뜨리고 있다는 것입니다.
- 먼저 PATCH는 맵/사전/키 값 개체에서 작동하도록 정의되어 있지만 집합에서 사용됩니다.
- 를 정말로는, 을 사용할 필요가 있습니다 「 」 「 」 「 」 「 」 「 」 「 」
t: Set<T> → Map<T, Boolean>
되어 있습니다.x in A iff t(A)(x) == True
이 정의를 사용하면 패치 적용은 유휴 상태로 남습니다. - 예에서는 이 합니다.먼저 오브젝트에 대해 ID가 생성되는 이유는 무엇입니까?제생 ??다르게 ).
{id: 1, email: "me@site.example"}
해야 한다{email: "me@site.example"}
그렇지 않으면 프로그램은 항상 파손되어 패치 적용이 불가능할 수 있습니다).세트에 대해 확인하기 전에 ID가 생성되면 프로그램이 다시 고장납니다.
이 예에서는 PUT가 고장난 것의 절반을 절단함으로써 빈약하지 않은 것을 예로 들 수 있습니다.
- 생성된 추가 기능의 예로는 버전 관리를 들 수 있습니다.단일 객체의 변경 수를 기록할 수 있습니다.이 경우 PUT은 아이돌이 아닙니다.
PUT /user/12 {email: "me@site.example"}
이 되다{email: "...", version: 1}
번째, 첫 번째{email: "...", version: 2}
두 번째에요. - ID를 조작하면 오브젝트가 갱신될 때마다 새로운 ID가 생성되어 비 아이돌 PUT가 발생할 수 있습니다.
위의 예들은 모두 사람들이 마주칠 수 있는 자연스러운 예들이다.
마지막으로, PATCH는 글로벌하게 기능하지 않는 것이 좋습니다.그렇지 않으면 원하는 효과를 얻을 수 없습니다.나머지 정보는 건드리지 않고 사용자의 전자 메일 주소를 변경하고 동일한 리소스에 액세스하는 다른 파티의 변경 내용을 덮어쓰지 않을 수 있습니다.
여기 아주 좋은 설명이 있습니다.
https://blog.segunolalive.com/posts/restful-api-design-%E2%80%94-put-vs-patch/ # : ~ : text = % % 205789 、 not % 20 required % 20 to % 20be % 20idempotent 。
일반 페이로드 - // 플롯 1의 하우스 {주소: '플롯 1', 소유자: '세건', 유형: '듀플렉스', 색상: '녹색', 방: '5', 주방: '1', 창: 20} PUT 업데이트 - // 플롯 1의 하우스 윈도우를 업데이트하기 위한 PUT 요청 페이로드: '세건' 유형:위의 페이로드에서는 창을 20에서 21로 업데이트하려고 합니다.
이제 PATH 페이로드 - // 하우스 { windows: 21}의 창을 업데이트하도록 요청 페이로드 패치 적용
PATCH는 idempotent가 아니기 때문에 실패한 요구는 네트워크에서 자동으로 재시도되지 않습니다.또한 존재하지 않는 URL(존재하지 않는 건물의 현관문을 교체하려고 하는 등)에 PATCH 요구가 이루어진 경우 PUT과 달리 새로운 리소스를 작성하지 않고 실패합니다.PAT는 payload를 사용하여 새로운 리소스를 만듭니다.그러고 보니 집주소에 문이 하나밖에 없는 것은 이상할 것 같습니다.
제가 이해한 내용을 평신도 용어로 요약해 보겠습니다(아마 도움이 될 것입니다).
패치가 완전히 유효하지는 않습니다(아무도 엔티티의 다른 필드를 변경하지 않는 이상적인 상황일 수 있습니다).
이상적이지 않은 상황(실제)에서는 다른 패치 조작에 의해 오브젝트의 다른 필드가 변경되어 두 작업 모두 Idempotent가 아닙니다(즉, 양쪽의 변경 대상이 되는 리소스가 어느 한쪽의 시점에서 「잘못」으로 돌아오는 것을 의미합니다).
따라서 모든 상황을 망라하지 않으면 Idempotent라고 할 수 없습니다.어떤 이들에게는 그다지 중요하지 않을 수도 있지만 다른 이들에게는
추가 정보 중 하나1개만 추가하면 데이터의 일부만 엔티티 전체가 아닌 PUT 요구에 비해 PATCH 요구는 대역폭을 적게 사용합니다.따라서 (1~3개의 레코드)와 같은 특정 레코드의 업데이트에 PATS 요청을 사용하여 대량의 데이터를 업데이트하십시오.이상입니다. 너무 많이 생각하거나 너무 걱정하지 마세요.
언급URL : https://stackoverflow.com/questions/28459418/use-of-put-vs-patch-methods-in-rest-api-real-life-scenarios
'programing' 카테고리의 다른 글
각도 변경 방법JS 데이터가 범위를 벗어났습니까? (0) | 2023.02.10 |
---|---|
RestTemplate로 데이터를 가져올 때 항상 403이 표시되는 이유는 무엇입니까? (0) | 2023.02.10 |
JavaScript for loop을 사용하여 json을 작성하는 방법 (0) | 2023.02.10 |
카테고리를 보호하기 위해 Woocommerce의 Shop 페이지를 비활성화합니다. (0) | 2023.02.10 |
Wordpress 사용자 지정기에 "바로 가기 편집" 아이콘을 추가하는 방법 (0) | 2023.02.10 |