REST API에서 PATCH 또는 PUT을 사용해야합니까?


274

다음 시나리오에 적합한 방법으로 나머지 끝점을 디자인하고 싶습니다.

그룹이 있습니다. 각 그룹에는 상태가 있습니다. 관리자가 그룹을 활성화 또는 비활성화 할 수 있습니다.

엔드 포인트를 다음과 같이 디자인해야합니까?

PUT /groups/api/v1/groups/{group id}/status/activate

또는

PATCH /groups/api/v1/groups/{group id}

with request body like 
{action:activate|deactivate}

1
둘 다 괜찮습니다. 그러나 JSON PATCH 형식 ( tools.ietf.org/html/rfc6902 ) 에 대한 RFC를 살펴보십시오 . PATCH는 페이로드에 대해 일종의 diff / patch 문서를 얻을 것으로 예상합니다 (그리고 원시 JSON은 그중 하나가 아닙니다).
Jørn Wildt 2016 년

1
@ JørnWildt 아니오, PUT은 끔찍한 선택입니다. 거기에 무엇을 넣고 있습니까? PATCH는 합리적인 옵션입니다. 이 경우 질문에 제시된 PATCH 형식을 사용하고 PUT 메소드 만 사용할 수 있습니다. PUT 예제가 잘못되었습니다.
thecoshman 2016 년

3
클라이언트가 PUT으로 GET하고 수정할 수있는 독립 실행 형 리소스로 하나 이상의 속성을 노출하는 데 아무런 문제가 없습니다. 그러나 그렇습니다. 그러면 URL은 "active"또는 "inactive"또는 GET을 넣어 현재 상태를 읽을 수있는 / groups / api / v1 / groups / {group id} / status 여야합니다.
Jørn Wildt

3
여기 PATCH 정말 사용하는 방법의 좋은 설명입니다 : williamdurand.fr/2014/02/14/please-do-not-patch-like-an-idiot
rishat

4
" activate"는 적절한 RESTful 구성이 아닙니다. 아마도 status"active"또는 "deactive" 로 업데이트하려고합니다 . 이 경우 .../status본문에서 "active"또는 "deactive"문자열 을 사용하여 PATCH 할 수 있습니다 . 당신은 부울에서 업데이트하려는 경우 또는 status.active, 당신은에 패치 할 수 있습니다 .../status/active본문에 부울로
Augie 가드너

답변:


328

PATCH그룹 ID - 방법은 기존 자원을 업데이트하고 같이 올바른 선택 여기에있다. 리소스를 완전히 교체 하는 PUT경우에만 사용해야합니다 .

부분 자원 수정에 대한 추가 정보는 RFC 5789에 있습니다. 구체적으로, PUT방법은 다음과 같이 설명된다 :

HTTP (Hypertext Transfer Protocol)를 확장하는 일부 응용 프로그램에는 부분 리소스 수정 기능이 필요합니다. 기존 HTTP PUT 메소드는 문서를 완전히 대체 할 수만 있습니다. 이 제안은 기존 HTTP 리소스를 수정하기 위해 새로운 HTTP 메서드 인 PATCH를 추가합니다.


1
공정하게하기 위해 문자열 'activate'또는 'deactivate'를 리소스에 넣을 수 있습니다. 토글해야 할 것이 하나 뿐인 것처럼 보이므로 완전히 교체하는 것은 그리 큰 일이 아닙니다. 그리고 그것은 (소수의) 작은 요청을 허용합니다.
thecoshman 2016 년

35
RFC 5789는 여전히 제안 단계에 있으며 공식적으로 승인되지 않았으며 현재는 '이라 타 존재'로 표시되어 있습니다. 이 '모범 사례'는 논란의 여지가 많으며 기술적으로 PATCH는 아직 HTTP 표준의 일부가 아닙니다.
fishpen0

4
몇 년 후 내 2 센트 만 : 상태 자체를 리소스로 간주 할 수 있으며, 그렇다면 / status에 PUT을 사용하면 기술적으로 해당 엔드 포인트의 상태 리소스를 대체하게됩니다.
Jono Stewart의

3
나는 그것이 "the"RFC이지만 문서에 대해 감히 논쟁 할 것이다. 문서에서는 PATCH를 사용하여 리소스의 일부만 수정해야한다고 언급하지만 PATCH 메서드가 비등 전성 메서드로 정의 된 중요한 것은 생략했습니다. 왜? 전체 리소스의 업데이트 / 교체를 염두에두고 PUT 메서드를 만든 경우 리소스의 일부만 업데이트하는 것이 목적이라면 PATCH 메서드가 PUT과 같은 dem 등식 메서드로 생성되지 않은 이유는 무엇입니까? 필자는 "a = 5"(PUT) 및 "a = a + 5"(PATCH)와 같이 업데이트의 dem 등성에서 더 많은 차이를 보입니다. 둘 다 전체 리소스를 업데이트 할 수 있습니다.
Mladen B.

179

REST 의 R 은 자원을 나타냅니다.

(Representational의 약자이기 때문에 사실이 아니지만 REST에서 리소스의 중요성을 기억하는 것이 좋습니다.)

정보 PUT /groups/api/v1/groups/{group id}/status/activate: "활성화"를 업데이트 하지 않습니다 . "활성화"는 문제가 아니라 동사입니다. 동사는 결코 좋은 자원이 아닙니다. 경험 법칙 : 동사 인 동작이 URL에 있으면 RESTful이 아닐 수 있습니다.

당신은 대신 무엇을하고 있습니까? 그룹에서 활성화 를 "추가", "제거"또는 "업데이트" 하거나 원하는 경우 : 그룹에서 "상태"-자원 조작. 개인적으로, "상태"는 "상태"개념보다 덜 모호하기 때문에 "활성화"를 사용합니다. 상태를 만드는 것이 모호하며 활성화를 만드는 것은 아닙니다.

  • POST /groups/{group id}/activation 활성화를 작성하거나 작성을 요청합니다.
  • PATCH /groups/{group id}/activation기존 활성화에 대한 일부 세부 사항을 업데이트합니다. 그룹에는 하나의 활성화 만 있기 때문에 어떤 활성화 리소스를 참조하는지 알고 있습니다.
  • PUT /groups/{group id}/activation이전 활성화를 삽입하거나 바꿉니다. 그룹에는 하나의 활성화 만 있기 때문에 어떤 활성화 리소스를 참조하는지 알고 있습니다.
  • DELETE /groups/{group id}/activation 활성화를 취소하거나 제거합니다.

이 패턴은 그룹의 "활성화"에 지불, 우편 발송 등 부작용이있을 때 유용합니다. POST 및 PATCH 만 이러한 부작용이있을 수 있습니다. 예를 들어 활성화 삭제로 메일을 통해 사용자에게 알려야하는 경우 DELETE가 올바른 선택이 아닙니다. 이 경우 당신은 아마 할 비활성화 리소스를 만들 : POST /groups/{group_id}/deactivation.

표준 계약을 통해 클라이언트와 클라이언트와 사용자 사이의 모든 프록시와 계층에 대해 명확하게 재 시도 할 수있는시기와 그렇지 않은시기를 알 수 있으므로 이러한 지침을 따르는 것이 좋습니다 . 클라이언트가 비정상적인 무선 랜을 가지고 있고 사용자가 "비활성화"를 클릭하면 다음을 트리거한다고 가정 해 봅시다 DELETE. 실패하면 클라이언트가 404, 200 또는 처리 할 수있는 다른 것을 얻을 때까지 단순히 다시 시도 할 수 있습니다. 그러나 그것이 트리거되면 POST to deactivation다시 시도하지 않는다는 것을 알고 있습니다 : POST는 이것을 의미합니다.
모든 클라이언트는 이제 계약을 맺었으며, 이는 HTTP 라이브러리가 백엔드 호출을 계속 재 시도하기 때문에 "그룹이 비활성화되었습니다"라는 42 개의 이메일을 보내지 않도록 보호합니다.

단일 속성 업데이트 : PATCH 사용

PATCH /groups/{group id}

속성을 업데이트하려는 경우 예를 들어 "상태"는 설정할 수있는 그룹의 속성 일 수 있습니다. "상태"와 같은 속성은 종종 화이트리스트 값으로 제한하기에 적합한 후보입니다. 예제는 정의되지 않은 JSON 스키마를 사용합니다.

PATCH /groups/{group id} { "attributes": { "status": "active" } }
response: 200 OK

PATCH /groups/{group id} { "attributes": { "status": "deleted" } }
response: 406 Not Acceptable

부작용없이 리소스를 교체하려면 PUT을 사용하십시오.

PUT /groups/{group id}

전체 그룹을 교체하려는 경우. 이것은 반드시 서버가 실제로 새 그룹을 만들고 이전 그룹을 버리는 것을 의미하지는 않습니다. 예를 들어 id는 동일하게 유지 될 수 있습니다. 그러나 클라이언트의 경우 이는 PUT 의미 할 수있는 것입니다. 클라이언트는 서버의 응답에 따라 완전히 새로운 항목을 얻는다고 가정해야합니다.

클라이언트는 PUT요청이있을 경우 항상 전체 항목을 보내야하며 새 항목을 작성하는 데 필요한 모든 데이터가 있어야합니다. 일반적으로 POST 작성과 동일한 데이터가 필요합니다.

PUT /groups/{group id} { "attributes": { "status": "active" } }
response: 406 Not Acceptable

PUT /groups/{group id} { "attributes": { "name": .... etc. "status": "active" } }
response: 201 Created or 200 OK, depending on whether we made a new one.

매우 중요한 요구 사항은 PUTdem 등원입니다. 그룹을 업데이트하거나 활성화를 변경할 때 부작용이 필요한 경우을 사용해야합니다 PATCH. 따라서 업데이트로 인해 메일 발송이 발생하면를 사용하지 마십시오 PUT.


3
이것은 나에게 매우 유익했다. "이 패턴은 그룹의"활성화 "에 부작용이있는 경우에 유용합니다.
Abdul

1
@ Abdul,이 패턴은 많은 이유로 유용하지만 WRT 부작용으로 클라이언트에게 매우 분명해야합니다. 동작에 미치는 영향. 예를 들어, iOS 앱이 전체 주소록을 "연락처"로 전송하기로 결정하면 연락처의 생성, 업데이트, 삭제 등의 부작용이 무엇인지가 분명해야합니다. 예를 들어 모든 연락처를 대량 메일로 발송하지 않기 위해.
berkes

1
RESTfull에서 PUT은 엔티티 ID를 변경할 수도 있습니다. 예를 들어 병렬 키가 실패 할 수있는 기본 키 ID입니다. (예를 들어 전체 엔티티를 업데이트하면 일부 행을 삭제하고 새로운 행을 추가해야하므로 새 엔티티를 작성해야합니다) PATCH가이를 수행 할 수 없어야하는 경우 다른 "애플리케이션"에 영향을주지 않고 무제한의 PATCH 요청을 허용합니다.
Piotr Kula

1
매우 유용한 답변. 감사! 또한 PUT / PATCH의 차이점은 전체 / 부분 업데이트가 아니라 다른 dem 등성이라는 점을 지적하면서 Luke의 답변과 마찬가지로 주석을 추가합니다. 이것은 실수가 아니며 의도적 인 결정이었습니다. HTTP 메소드의 사용법을 결정할 때 많은 사람들이 이것을 고려하지 않는다고 생각합니다.
Mladen B.

1
모델과 같은 @richremer 서비스는 내부 추상화입니다. REST- 종료점 및 ORM 모델 또는 데이터베이스 테이블간에 1-1 관계를 요구하는 것은 좋지 않은 추상화와 마찬가지로 서비스를 노출하는 추상화도 좋지 않습니다. 외부 API는 도메인 모델과 통신해야합니다. 내부적으로 구현하는 방법은 API와 관련이 없습니다. API를 변경하지 않고도 ActivationService에서 CQRS 기반 활성화 플로우로 자유롭게 이동할 수 있어야합니다.
berkes

12

리소스 'group'에 많은 속성이 있기 때문에 PATCH를 사용하는 것이 좋습니다.이 경우 활성화 필드 만 업데이트합니다 (부분 수정)

RFC5789에 따라 ( https://tools.ietf.org/html/rfc5789 )

기존 HTTP PUT 메소드는 문서를 완전히 대체 할 수만 있습니다. 이 제안은 기존 HTTP 리소스를 수정하기 위해 새로운 HTTP 메서드 인 PATCH를 추가합니다.

또한 자세한 내용은

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

PATCH 의 응용 프로그램에 의해 작성되거나 기존의 수정 될 수 있습니다 .

PATCH는 [RFC2616], 섹션 9.1에 정의 된대로 안전하거나 dem 등하 지 않습니다.

클라이언트는 PUT 대신 PATCH를 사용할시기를 선택해야합니다. 예를
들어, 패치 문서 크기가
PUT에 사용될 새 자원 데이터 의 크기보다 큰 경우
PATCH 대신 PUT을 사용하는 것이 좋습니다. POST는 광범위하게 사용되며
서버가 선택하는 경우 PUT 및 PATCH와 유사한 작업을 포함 할 수 있으므로 POST와 비교하기가 훨씬 어렵습니다 . 경우
작업이 예측 가능한 방법으로 요청 - URI에 의해 식별되는 리소스를 수정하지 않습니다, POST 대신 패치의 고려되어야한다
또는 PUT.

PATCH의 응답 코드는

204 응답 코드는 응답에 메시지 본문 (200 코드의 응답이 포함)을 전달하지 않기 때문에 사용됩니다. 다른 성공 코드도 사용될 수 있습니다.

thttp : //restcookbook.com/HTTP%20Methods/patch/도 참조하십시오

주의 사항 : PATCH를 구현하는 API는 원자 적으로 패치해야합니다. GET에 의해 요청 될 때 리소스가 반 패치 될 수 없어야합니다.


7

REST 아키텍처 스타일을 사용하여 API를 설계하려고하므로 유스 케이스를 고려하여 자원으로 공개하기에 충분한 개념을 결정해야합니다. 그룹의 상태를 하위 자원으로 표시하기로 결정한 경우 다음 URI를 제공하고 GET 및 PUT 메소드 모두에 대한 지원을 구현할 수 있습니다.

/groups/api/groups/{group id}/status

수정을위한 PATCH에 대한이 접근 방식의 단점은 원자 및 트랜잭션 방식으로 그룹의 둘 이상의 속성을 변경할 수 없다는 것입니다. 트랜잭션 변경이 중요한 경우 PATCH를 사용하십시오.

상태를 그룹의 하위 리소스로 공개하기로 결정한 경우 그룹을 나타내는 링크 여야합니다. 예를 들어 에이전트가 그룹 123을 가져오고 XML을 수락하면 응답 본문에 다음이 포함될 수 있습니다.

<group id="123">
  <status>Active</status>
  <link rel="/linkrels/groups/status" uri="/groups/api/groups/123/status"/>
  ...
</group>

하이퍼 링크는 REST 아키텍처 스타일 의 애플리케이션 상태 조건 엔진으로 하이퍼 미디어 하이퍼 .


0

나는 일반적으로 activate/ deactivate하위 리소스 (와 Link헤더로 연결) 와 같이 조금 더 간단한 것을 선호합니다 rel=service.

POST /groups/api/v1/groups/{group id}/activate

또는

POST /groups/api/v1/groups/{group id}/deactivate

소비자의 경우이 인터페이스는 매우 간단하며 "활성화"를 개별 리소스로 개념화 할 필요없이 REST 원칙을 따릅니다.


0

그러한 행동을 구현하는 한 가지 가능한 옵션은

PUT /groups/api/v1/groups/{group id}/status
{
    "Status":"Activated"
}

사람의 필요를 비활성화 할 수 있다면 분명히, PUT해야합니다Deactivated JSON에 상태를 표시합니다.

대량 활성화 / 비활성화가 필요한 경우 PATCH게임을 시작할 수 있습니다 (정확한 그룹이 아니라 groups리소스).

PATCH /groups/api/v1/groups
{
    { “op”: “replace”, “path”: “/group1/status”, “value”: “Activated” },
    { “op”: “replace”, “path”: “/group7/status”, “value”: “Activated” },
    { “op”: “replace”, “path”: “/group9/status”, “value”: “Deactivated” }
}

일반적으로 이것은 @Andrew Dobrowolski가 제안한 아이디어이지만 정확한 실현에는 약간의 변화가 있습니다.

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