REST API는 부분적으로 수정 가능한 자원에 대한 PUT 요청을 어떻게 처리해야합니까?


46

HTTP GET요청 에 대한 응답으로 REST API 가 하위 오브젝트에 일부 추가 데이터를 리턴 한다고 가정하십시오 owner.

{
  id: 'xyz',
  ... some other data ...
  owner: {
    name: 'Jo Bloggs',
    role: 'Programmer'
  }
}

분명히, 우리는 누군가가 PUT뒤로 물러 설 수 있기를 원하지 않습니다.

{
  id: 'xyz',
  ... some other data ...
  owner: {
    name: 'Jo Bloggs',
    role: 'CEO'
  }
}

그리고 성공하십시오. 실제로, 이 경우에는 잠재적으로 성공할 수있는 방법 도 구현 하지 않을 것 입니다.

그러나이 질문은 하위 객체에 관한 것이 아닙니다. 일반적으로 PUT 요청에서 수정할 수없는 데이터로 무엇을해야합니까?

PUT 요청에서 누락되어야합니까?

조용히 폐기해야합니까?

확인해야하고 해당 속성의 이전 값과 다른 경우 응답에 HTTP 오류 코드를 반환합니까?

아니면 전체 JSON을 보내는 대신 RFC 6902 JSON 패치를 사용해야합니까?


2
이 모든 것이 작동합니다. 나는 그것이 당신의 요구 사항에 달려 있다고 생각합니다.
Robert Harvey

최소한 놀람의 원칙이 PUT 요청에서 누락되어야 함을 나타냅니다. 가능하지 않은 경우 확인하고 다르면 오류 코드와 함께 리턴하십시오. 자동 삭제가 최악입니다 (사용자 전송이 변경 될 것으로 예상하고 "200 OK"라고 말함).
Maciej Piechotka

2
@MaciejPiechotka 문제는 삽입이나 가져 오기와 같은 동일한 모델을 사용하지 않는다는 것입니다. 동일한 모델을 사용하고 필드 인증 규칙을 간단하게 사용하여 값을 입력하면 변경해서는 안되는 필드, 403 Forbidden을 반환하고 나중에 권한 부여가 허용되도록 설정되면 권한이 부여되지 않은 경우 401 Unauthorized를 얻습니다
Jimmy Hoffa

@ JimmyHoffa : 모델은 데이터 형식을 의미합니다 (사용 된 경우 선택에 따라 MVC Rest 프레임 워크에서 모델을 재사용 할 수 있기 때문에 OP는 언급하지 않았습니다)? 프레임 워크에 의해 제약을받지 않고 초기 오류가 약간 더 발견 가능하고 구현하기가 쉬운 다음 변경 사항을 확인하면 검색 가능성과 함께 갈 것입니다 (확인-필드 XYZ를 건 드리면 안됩니다). 어쨌든 폐기는 최악입니다.
Maciej Piechotka

답변:


46

W3C 사양 또는 REST의 비공식 규칙에는 해당 규칙과 PUT동일한 스키마 / 모델을 사용해야 한다는 규칙이 없습니다 GET.

그것들이 비슷 하다면 좋지만 , PUT약간 다르게하는 것은 드문 일이 아닙니다 . 예를 들어 GET편의상으로 반환되는 콘텐츠에 일종의 ID를 포함하는 많은 API를 보았습니다 . 그러나을 사용하면 PUT해당 ID는 URI에 의해 독점적으로 결정되며 내용에는 의미가 없습니다. 본문에서 발견 된 모든 ID는 자동으로 무시됩니다.

REST와 웹은 일반적으로 견고성 원칙밀접한 관련이 있습니다 . "자신이하는 일에 보수적이며, 받아들이는 것에 자유주의하십시오." 이것에 철학적으로 동의하면 해결책이 분명 PUT합니다. 요청 에서 유효하지 않은 데이터는 무시하십시오 . 이는 예와 같이 변경 불가능한 데이터와 알 수없는 필드와 같은 실제 넌센스에 모두 적용됩니다.

PATCH잠재적으로 또 다른 옵션이지만 PATCH실제로 부분 업데이트를 지원하지 않는 한 구현해서는 안됩니다 . 콘텐츠에 포함 된 특정 속성 만 업데이트PATCH 함을 의미 합니다 . 그것은 않습니다 하지 의미 전체 엔터티를 교체하지만, 일부 특정 분야를 제외 . 실제로 이야기하는 것은 실제로 부분 업데이트가 아니라 전체 업데이트, dem 등성이며 리소스의 일부만 읽기 전용입니다.

이 옵션을 선택하면 클라이언트가 읽기 전용 필드가 업데이트되지 않았 음을 명확하게 확인할 수 있도록 응답에서 실제 업데이트 된 엔티티와 함께 200 (OK) 다시 보내는 것이 좋습니다.

거기에 확실히 어떤 사람들 은 오류가 자원의 읽기 전용 부분을 업데이트하려고하는 것을 - 다른 방법을 생각한다. 전체 리소스가 읽기 전용이고 사용자가 해당 리소스를 업데이트하려고 시도한 경우 오류를 확실히 반환 할 수 있다는 근거가 있습니다 . 그것은 확실히 견고성 원칙에 위배되지만 API 사용자에게는 "자체 문서화"라고 생각할 수 있습니다.

이것에 대한 두 가지 규칙이 있습니다. 둘 다 원래 아이디어와 일치하지만 더 확장 할 것입니다. 첫 번째는 읽기 전용 필드가 내용에 나타나지 않도록하고 HTTP 400 (잘못된 요청)을 반환하는 것입니다. 인식 할 수 없거나 사용할 수없는 다른 필드가있는 경우 이러한 종류의 API도 HTTP 400을 반환해야합니다. 두 번째는 읽기 전용 필드가 현재 컨텐츠와 동일해야하고 값이 일치하지 않으면 409 (충돌)를 리턴하는 것입니다.

나는 409와의 평등 검사를 정말로 싫어한다. 왜냐하면 클라이언트가 GET현재 데이터를 검색하기 전에를 수행해야하기 때문 PUT이다. 그것은 좋지 않으며 아마도 어딘가에 대한 성능 저하로 이어질 것입니다. 또한 실제로 는 것을 의미한다 이에 대한 (금지)하지 같은 403을 전체 자원, 그것의 단지 일부를 보호됩니다. 따라서 견고성 원칙을 따르는 대신 절대적으로 유효성을 검사해야하는 경우 모든 요청을 확인 하고 추가 또는 쓰기 불가능한 필드가있는 경우 400을 반환해야합니다.

400 / 409 / 무엇에 특정 문제에 대한 정보와 문제 해결 방법이 포함되어 있는지 확인하십시오.

이 두 가지 방법 모두 유효하지만 견고성 원칙에 따라 전자를 선호합니다. 대규모 REST API를 사용한 경험이 있다면 이전 버전과의 호환성의 가치에 감사하게 될 것입니다. 기존 필드를 제거하거나 읽기 전용으로 설정하기로 결정한 경우 서버가 해당 필드를 무시하고 이전 클라이언트가 계속 작동하면 이전 버전과 호환되는 변경 사항입니다. 그러나 내용에 대해 엄격한 유효성 검사를 수행하면 더 이상 이전 버전과 호환 되지 않으며 이전 클라이언트의 작동이 중지됩니다. 전자는 일반적으로 API 관리자와 클라이언트 모두에게 적은 작업을 의미합니다.


1
좋은 대답과 공감. 그러나 "나는 기존 필드를 제거하거나 읽기 전용으로 설정하기로 결정한 경우 서버가 해당 필드를 무시하고 이전 클라이언트가 계속 작동하면 이전 버전과 호환되는 변경 사항입니다. " 클라이언트가이 제거 / 새로 읽기 전용 필드에 의존하는 경우에도 여전히 앱의 전체 동작에 영향을 미치지 않습니까? 필드를 제거하는 경우 데이터를 무시하는 대신 명시 적으로 오류를 생성하는 것이 좋습니다. 그렇지 않으면 클라이언트는 이전에 작동하던 업데이트가 실패한다는 것을 전혀 모릅니다.
rinogo

이 답변은 잘못되었습니다. RFC2616의 두 가지 이유로 : 1. (섹션 9.1.2) PUT은 독립적이어야합니다. 여러 번 입력하면 한 번만 넣는 것과 동일한 결과가 생성됩니다. 2. 자원 변경은 그 밖의 자원 변경 요청이없는 경우 제출 된 실체를 반환해야합니다.
brunoais

1
불변 값이 요청에서 전송 된 경우에만 동등성 검사를 수행하면 어떻게됩니까? 나는 이것이 당신에게 두 세계의 최고를 제공한다고 생각합니다. 클라이언트가 GET을 수행하도록 강요하지 않으며, 불변 값으로 유효하지 않은 값을 보낸 경우 여전히 잘못된 것을 알립니다.
Ahmad Abdelghany '

고맙게도 경험에서 나온 마지막 단락에서 심도있는 비교는 내가 찾던 것입니다.
10

9

pot 효능

RFC에 이어 PUT은 리소스에 전체 개체를 제공해야합니다. 이것의 주된 이유는 PUT이 dem 등원이어야하기 때문입니다. 이는 요청이 서버에서 동일한 결과로 평가되어야한다는 것을 의미합니다.

부분 업데이트를 허용하면 더 이상 강력한 업데이트가 될 수 없습니다. 두 명의 고객이있는 경우 클라이언트 A와 B는 다음 시나리오로 발전 할 수 있습니다.

클라이언트 A는 리소스 이미지에서 사진을 가져옵니다. 여기에는 이미지에 대한 설명이 포함되며 여전히 유효합니다. 클라이언트 B는 새로운 이미지를 넣고 그에 따라 설명을 업데이트합니다. 사진이 변경되었습니다. 고객 A는 자신이 원하는대로 이미지를 설명하기 때문에 설명을 변경할 필요가 없습니다.

이로 인해 불일치가 발생하고 이미지에 잘못된 메타 데이터가 첨부되었습니다!

더 성가신 것은 모든 중개자가 요청을 반복 할 수 있다는 것입니다. 어떻게 든 PUT이 실패했는지 결정합니다.

PUT의 의미는 변경할 수 없습니다 (오용 할 수는 있지만).

다른 옵션

운 좋게 또 다른 옵션이 있습니다. 이것은 PATCH입니다. PATCH는 구조를 부분적으로 업데이트 할 수있는 방법입니다. 단순히 부분 구조를 보낼 수 있습니다. 간단한 응용 프로그램의 경우 문제가 없습니다. 이 방법이 반드시 강력한 것은 아닙니다. 클라이언트는 다음 형식으로 요청을 보내야합니다.

PATCH /file.txt HTTP/1.1
Host: www.example.com
Content-Type: application/example
If-Match: "e0023aa4e"
Content-Length: 20
{fielda: 1, fieldc: 2}

그리고 서버는 성공을 알리기 위해 204 (콘텐츠 없음)로 회신 할 수 있습니다. 오류가 발생하면 구조의 일부를 업데이트 할 수 없습니다. PATCH 방법은 원 자성입니다.

이 방법의 단점은 모든 브라우저가이를 지원하지는 않지만 REST 서비스에서 가장 자연스러운 옵션이라는 것입니다.

패치 요청 예 : http://tools.ietf.org/html/rfc5789#section-2.1

JSON 패치

json 옵션은 매우 포괄적이며 흥미로운 옵션입니다. 그러나 제 3자를 위해 구현하기가 어려울 수 있습니다. 사용자 기반이이를 처리 할 수 ​​있는지 결정해야합니다.

또한 명령을 부분 구조로 변환하는 작은 인터프리터를 빌드해야하기 때문에 다소 복잡합니다. 모델을 업데이트하는 데 사용할 것입니다. 이 명령은 제공된 명령이 의미가 있는지 확인해야합니다. 일부 명령은 서로를 취소합니다. (필드 작성, 필드 삭제). 클라이언트 측에 디버그 시간을 제한하기 위해 이것을 클라이언트에 다시보고하고 싶다고 생각합니다.

그러나 시간이 있다면 이것은 정말 우아한 해결책입니다. 물론 필드의 유효성을 검사해야합니다. 이것을 PATCH 메소드와 결합하여 REST 모델에 머무를 수 있습니다. 그러나 POST는 여기에 적합 할 것이라고 생각합니다.

나쁜가

PUT 옵션을 사용하기로 결정한 경우 다소 위험합니다. 그런 다음 최소한 오류를 버리지 않아야합니다. 사용자에게는 일정한 기대치가 있으며 (데이터가 업데이트 됨)이 문제를 해결하면 일부 개발자에게 좋지 않은 시간을주게됩니다.

409 충돌 또는 403 금지로 플래그를 다시 지정할 수 있습니다. 업데이트 프로세스를 보는 방법에 따라 다릅니다. 규칙 세트 (시스템 중심)로 보면 충돌이 더 좋아질 것입니다. 이러한 필드는 업데이트 할 수 없습니다. (규칙과 충돌). 인증 문제 (사용자 중심)로 보이면 금지 된 것으로 반환해야합니다. 포함 :이 필드를 변경할 권한이 없습니다.

여전히 사용자가 수정 가능한 모든 필드를 보내도록해야합니다.

이를 적용하는 합리적인 옵션은 수정 가능한 데이터 만 제공하는 하위 리소스로 설정하는 것입니다.

개인적인 의견

개인적으로 간단한 패치 모델을 사용하고 (브라우저를 사용할 필요가 없다면) 나중에 JSON 패치 프로세서로 확장합니다. 이것은 mimetypes를 차별화하여 수행 할 수 있습니다 : mime type of json patch :

응용 프로그램 / json-patch

그리고 json : application / json-patch

두 단계로 쉽게 구현할 수 있습니다.


3
dem 등성 예가 이해가되지 않습니다. 설명을 변경하거나 변경하지 마십시오. 어느 쪽이든, 당신은 매번 같은 결과를 얻을 것입니다.
Robert Harvey

1
네 말이 맞아 잠자리에들 시간이야 편집 할 수 없습니다. PUT 요청으로 모든 데이터를 전송하는 합리적인 이유에 대한 예입니다. 포인터 주셔서 감사합니다.
Edgar Klerks

나는 이것이 3 년 전인 것을 알고 있지만 RFC에서 "PUT이 전체 객체를 리소스에 전달해야 할 것"에 대한 자세한 정보를 찾을 수있는 곳을 알고 있습니다. 나는 이것이 다른 곳에서 언급 된 것을 보았지만 사양에서 어떻게 정의되는지보고 싶습니다.
CSharper 2016 년

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