[rest] RESTful 서비스에서 부분 업데이트에 대한 모범 사례

고객 관리 시스템을 위해 RESTful 서비스를 작성 중이며 레코드를 부분적으로 업데이트하는 모범 사례를 찾으려고 노력하고 있습니다. 예를 들어, 발신자가 GET 요청으로 전체 레코드를 읽을 수 있기를 원합니다. 그러나 업데이트하려면 상태를 ENABLED에서 DISABLED로 변경하는 것과 같이 레코드의 특정 작업 만 허용됩니다. (이보다 더 복잡한 시나리오가 있습니다)

보안상의 이유로 호출자가 업데이트 된 필드만으로 전체 레코드를 제출하지 않기를 원합니다 (과도한 느낌).

URI를 구성하는 권장 방법이 있습니까? REST 책을 읽을 때 RPC 스타일 호출은 눈살을 찌푸리는 것처럼 보입니다.

다음 통화에서 ID가 123 인 고객의 전체 고객 레코드를 반환하는 경우

GET /customer/123
<customer>
    {lots of attributes}
    <status>ENABLED</status>
    {even more attributes}
</customer>

상태를 어떻게 업데이트해야합니까?

POST /customer/123/status
<status>DISABLED</status>

POST /customer/123/changeStatus
DISABLED

...

업데이트 : 질문을 보완합니다. ‘비즈니스 로직 호출’을 REST API에 어떻게 통합합니까? 합의 된 방법이 있습니까? 모든 방법이 본질적으로 CRUD 인 것은 아닙니다. ‘ sendEmailToCustomer (123) ‘, ‘ mergeCustomers (123, 456) ‘, ‘ countCustomers () ‘ 와 같은 일부는 더 복잡합니다.

POST /customer/123?cmd=sendEmail

POST /cmd/sendEmail?customerId=123

GET /customer/count



답변

기본적으로 두 가지 옵션이 있습니다.

  1. 사용 PATCH(하지만 정확하게 발생하는 것을 지정하는 고유 한 미디어 유형을 정의해야 함)

  2. 사용 POST하위 자원 및 Location 헤더가 주요 자원을 가리키는과 303 페이지의 기타를 반환합니다. 303의 목적은 클라이언트에게 “POST를 수행했으며 그 결과 다른 리소스가 업데이트 된 것입니다. 어떤 리소스의 위치 헤더를 참조하십시오.” POST / 303은 일부 주요 자원의 상태를 구축하기 위해 자원에 반복적으로 추가하기위한 것이며 부분 업데이트에 완벽하게 적합합니다.


답변

부분 업데이트에는 POST를 사용해야합니다.

고객 123의 필드를 업데이트하려면 / customer / 123에 POST를 만드십시오.

상태 만 업데이트하려면 / customer / 123 / status로 PUT 할 수도 있습니다.

일반적으로 GET 요청에는 부작용이 없어야하며 PUT은 전체 리소스를 작성 / 바꾸기위한 것입니다.

이것은 http://en.wikipedia.org/wiki/HTTP_PUT#Request_methods에서 볼 수 있듯이 HTTP에서 직접 수행됩니다 .


답변

json-patch 문서를 사용하여 부분 업데이트에 PATCH를 사용해야합니다 ( http://tools.ietf.org/html/draft-ietf-appsawg-json-patch-08 또는 http://www.mnot.net/ 참조). blog / 2012 / 09 / 05 / patch ) 또는 XML 패치 프레임 워크 ( http://tools.ietf.org/html/rfc5261 참조 ) 내 의견으로는, json-patch는 귀하의 비즈니스 데이터 종류에 가장 적합합니다.

JSON / XML 패치 문서가 포함 된 PATCH는 부분 업데이트를위한 매우 중요한 의미를 갖습니다. 원본 문서의 수정 된 복사본으로 POST를 사용하기 시작하면 부분 업데이트의 경우 누락 된 값 (또는 null 값)이 “이 속성을 무시합니다”또는 “이 속성을 empty value “-결국 해킹 된 솔루션으로 인해 결국에는 자신 만의 패치 형식이 만들어 질 것입니다.

http://soabits.blogspot.dk/2013/01/http-put-patch-or-post-partial-updates.html 에서보다 자세한 답변을 찾을 수 있습니다 .


답변

비슷한 문제가 발생합니다. 하위 리소스의 PUT은 단일 필드 만 업데이트하려는 경우 작동하는 것 같습니다. 그러나 때로는 여러 가지 사항을 업데이트하려고합니다. 일부 항목을 변경하는 옵션이있는 리소스를 나타내는 웹 양식을 생각하십시오. 사용자가 양식을 제출하면 여러 PUT이 생성되지 않아야합니다.

내가 생각할 수있는 두 가지 솔루션이 있습니다.

  1. 전체 리소스로 PUT을 수행하십시오. 서버 측에서 전체 자원이있는 PUT이 변경되지 않은 모든 값을 무시한다는 의미를 정의하십시오.

  2. 부분 리소스로 PUT을 수행하십시오. 서버 측에서이 의미를 병합으로 정의하십시오.

2는 1의 대역폭 최적화입니다. 자원이 일부 필드가 필수 필드 인 경우 (프로토 버퍼 생각) 1이 유일한 옵션입니다.

이 두 가지 접근 방식의 문제점은 필드를 지우는 방법입니다. 필드를 지우는 특수 널 값을 정의해야합니다 (특히 널 값은 프로토 버퍼에 대해 정의되지 않으므로 프로토 버퍼에 대해).

코멘트?


답변

상태를 수정하기 위해 RESTful 접근법은 리소스의 상태를 설명하는 논리적 하위 리소스를 사용하는 것입니다. 이 IMO는 상태가 줄어든 경우 매우 유용하고 깨끗합니다. 고객 리소스에 대한 기존 작업을 강요하지 않고도 API를보다 표현력있게 만듭니다.

예:

POST /customer/active  <-- Providing entity in the body a new customer
{
  ...  // attributes here except status
}

POST 서비스는 새로 작성된 고객을 id로 반환해야합니다.

{
    id:123,
    ...  // the other fields here
}

생성 된 리소스에 대한 GET은 리소스 위치를 사용합니다.

GET /customer/123/active

GET / customer / 123 / inactive는 404를 반환해야합니다.

PUT 조작의 경우 Json 엔티티를 제공하지 않고 상태 만 업데이트합니다.

PUT /customer/123/inactive  <-- Deactivating an existing customer

엔티티를 제공하면 고객의 컨텐츠를 업데이트하고 동시에 상태를 업데이트 할 수 있습니다.

PUT /customer/123/inactive
{
    ...  // entity fields here except id and status
}

고객 자원에 대한 개념적 하위 자원을 작성 중입니다. 또한 Roy Fielding의 자원에 대한 정의와 일치합니다. “… 자원은 특정 시점에서 맵핑에 해당하는 엔티티가 아닌 엔티티 세트에 대한 개념적 맵핑입니다.” 개념적 매핑은 status = ACTIVE 인 고객에게 능동적 인 고객입니다.

읽기 조작 :

GET /customer/123/active
GET /customer/123/inactive

다른 호출 중 하나가 상태 404를 반환해야하는 즉시 해당 호출을 수행하면 성공적인 출력에는 암시 적 상태가 포함되지 않을 수 있습니다. 물론 GET / customer / 123? status = ACTIVE | INACTIVE를 사용하여 고객 리소스를 직접 쿼리 할 수 ​​있습니다.

의미 체계가 혼동 될 수 있으므로 DELETE 작업이 흥미 롭습니다. 그러나이 개념 자원에 대해 해당 조작을 공개하지 않거나 비즈니스 논리에 따라이를 사용할 수 있습니다.

DELETE /customer/123/active

이를 통해 고객을 삭제 / 비활성화 상태 또는 반대 상태 (ACTIVE / INACTIVE)로 전환 할 수 있습니다.


답변

확장 된 질문에 추가 할 사항. 더 복잡한 비즈니스 활동을 완벽하게 설계 할 수 있다고 생각합니다. 그러나 당신은 사고 방식 / 절차 스타일을 제시하고 자원과 동사에 대해 더 많이 생각해야합니다.

메일 발송


POST /customers/123/mails

payload:
{from: x@x.com, subject: "foo", to: y@y.com}

이 자원 + POST의 구현은 메일을 발송합니다. 필요한 경우 / customer / 123 / outbox와 같은 것을 제공 한 다음 / customer / mails / {mailId}에 대한 리소스 링크를 제공 할 수 있습니다.

고객 수

검색 리소스처럼 처리 할 수 ​​있습니다 (페이징이 포함 된 검색 메타 데이터 및 고객 수를 제공하는 num-found 정보 포함).


GET /customers

response payload:
{numFound: 1234, paging: {self:..., next:..., previous:...} customer: { ...} ....}


답변

불완전한 / 부분 리소스를 업데이트하려면 PUT을 사용하십시오.

jObject를 매개 변수로 승인하고 해당 값을 구문 분석하여 자원을 업데이트 할 수 있습니다.

다음은 참조로 사용할 수있는 기능입니다.

public IHttpActionResult Put(int id, JObject partialObject)
{
    Dictionary<string, string> dictionaryObject = new Dictionary<string, string>();

    foreach (JProperty property in json.Properties())
    {
        dictionaryObject.Add(property.Name.ToString(), property.Value.ToString());
    }

    int id = Convert.ToInt32(dictionaryObject["id"]);
    DateTime startTime = Convert.ToDateTime(orderInsert["AppointmentDateTime"]);
    Boolean isGroup = Convert.ToBoolean(dictionaryObject["IsGroup"]);

    //Call function to update resource
    update(id, startTime, isGroup);

    return Ok(appointmentModelList);
}