developer tip

REST-본문에 ID를 넣을까요?

copycodes 2020. 10. 8. 08:08
반응형

REST-본문에 ID를 넣을까요?


클라이언트가 ID를 할당 할 수있는 사람들을위한 RESTful 리소스를 원한다고 가정 해 보겠습니다.

사람은 다음과 같습니다. {"id": <UUID>, "name": "Jimmy"}

이제 클라이언트는이를 어떻게 저장 (또는 "PUT")해야합니까?

  1. PUT /person/UUID {"id": <UUID>, "name": "Jimmy"} -이제 우리는 항상 확인해야하는 불쾌한 중복이 있습니다. 본문의 ID가 경로의 ID와 일치합니까?
  2. 비대칭 표현 :
    • PUT /person/UUID {"name": "Jimmy"}
    • GET /person/UUID 보고 {"id": <UUID>, "name": "Jimmy"}
  3. 본문에 ID 없음-위치에만 ID :
    • PUT /person/UUID {"name": "Jimmy"}
    • GET /person/UUID 보고 {"name": "Jimmy"}
  4. 의 어떤 종류의 POSTID를이 클라이언트에 의해 생성되기 때문에 좋은 아이디어처럼 보인다.

일반적인 패턴과 해결 방법은 무엇입니까? 위치에만있는 ID는 가장 독단적으로 올바른 방법처럼 보이지만 실제 구현을 더 어렵게 만듭니다.


다른 읽기 / 쓰기 모델을 사용하는 데 잘못된 것은 없습니다. 클라이언트는 서버가 추가 / 계산 된 요소가있는 다른 표현을 반환 할 수있는 하나의 리소스 표현을 작성할 수 있습니다 (또는 완전히 다른 표현 일 수도 있습니다. , 유일한 요구 사항은 PUT가 리소스를 생성하거나 교체해야한다는 것입니다).

그래서 나는 (2)의 비대칭 솔루션을 선택하고 작성할 때 서버 측에서 "불쾌한 중복 검사"를 피할 것입니다.

PUT /person/UUID {"name": "Jimmy"}

GET /person/UUID returns {"id": <UUID>, "name": "Jimmy"}

공개 API 인 경우 답장 할 때는 보수적이어야하지만 자유롭게 수락해야합니다.

즉, 1과 2를 모두 지원해야합니다. 3이 말이 안된다는 데 동의합니다.

1과 2를 모두 지원하는 방법은 요청 본문에 아무것도 제공되지 않은 경우 URL에서 ID를 가져오고 요청 본문에있는 경우 URL의 ID와 일치하는지 확인하는 것입니다. 둘이 일치하지 않으면 400 Bad Request 응답을 반환합니다.

사람 리소스를 반환 할 때는 보수적이어야하며 put에서 선택 사항이더라도 json에 항상 id를 포함하십시오.


이 문제에 대한 한 가지 해결책은 "애플리케이션 상태의 엔진으로서의 하이퍼 텍스트"또는 "HATEOAS"라는 다소 혼란스러운 개념을 포함합니다. 이는 REST 응답에 하이퍼 링크로 수행 할 사용 가능한 리소스 또는 작업이 포함되어 있음을 의미합니다. REST의 원래 개념의 일부였던이 방법을 사용하면 리소스의 고유 식별자 / ID 자체가 하이퍼 링크입니다. 예를 들어 다음과 같은 것을 가질 수 있습니다.

GET /person/<UUID> {"person": {"location": "/person/<UUID>", "data": { "name": "Jimmy"}}}

그런 다음 해당 리소스를 업데이트하려면 다음을 수행 할 수 있습니다 (의사 코드).

updatedPerson = person.data
updatedPerson.name = "Timmy"
PUT(URI: response.resource, data: updatedPerson)

이것의 한 가지 장점은 클라이언트가 사용자 ID의 서버 내부 표현에 대해 전혀 알 필요가 없다는 것입니다. 클라이언트가 ID를 발견 할 수있는 한 ID는 변경 될 수 있으며 URL 자체도 변경 될 수 있습니다. 예를 들어, 사람들의 컬렉션을 가져올 때 다음과 같은 응답을 반환 할 수 있습니다.

GET /people
{ "people": [
    "/person/1",
    "/person/2"
  ]
}

(물론 응용 프로그램의 필요에 따라 각 사람에 대한 전체 사람 개체를 반환 할 수도 있습니다.)

이 방법을 사용하면 리소스 및 위치 측면에서 개체를 더 많이 생각하고 ID 측면에서는 덜 생각합니다. 따라서 고유 식별자의 내부 표현은 클라이언트 논리에서 분리됩니다. HTTP의 기능을 사용하여 이전에 존재하던 RPC 시스템보다 느슨하게 결합 된 클라이언트-서버 아키텍처를 만드는 것이 REST의 원동력이었습니다. HATEOAS에 대한 자세한 내용은 Wikipedia 기사 와이 짧은 기사를 참조하십시오 .


이것은 이전에 질문 된 적이 있습니다. 토론은 살펴볼 가치가 있습니다.

RESTful GET 응답이 리소스의 ID를 반환해야합니까?

이것은 "휴식"이 무엇인지 아닌지 에 대한 논쟁에 빠지기 쉬운 질문 중 하나입니다 .

그만한 가치는 일관된 리소스의 관점에서 생각하고 방법간에 디자인을 변경하지 않습니다. 그러나 IMHO는 사용성 관점에서 가장 중요한 것은 전체 API에서 일관성이 있다는 것입니다!


삽입에서 URL에 ID를 추가 할 필요가 없습니다. 이런 식으로 PUT에서 ID를 보내면 기본 키를 변경하는 UPDATE로 해석 될 수 있습니다.

  1. 끼워 넣다:

    PUT /persons/ 
      {"id": 1, "name": "Jimmy"}
    HTTP/1.1 201 Created     
      {"id": 1, "name": "Jimmy", "other_field"="filled_by_server"}
    
    GET /persons/1
    
    HTTP/1.1 200 OK
      {"id": 1, "name": "Jimmy", "other_field"="filled_by_server"}  
    
  2. 최신 정보

    PUT /persons/1 
         {"id": "2", "name": "Jimmy Jr"} - 
    HTTP/1.1 200 OK
         {"id": "2", "name": "Jimmy Jr", "other_field"="filled_by_server"}
    
    GET /persons/2 
    
    HTTP/1.1 200 OK
         {"id": "2", "name": "Jimmy Jr", "other_field"="updated_by_server"}
    

JSON API는 이 표준을 해결해 새 개체에 대한 링크 삽입 또는 업데이트 된 개체를 반환 몇 가지 문제를 사용합니다. 일부 업데이트 또는 삽입에는 추가 필드를 변경하는 비즈니스 논리가 포함될 수 있습니다.

또한 삽입 및 업데이트 후 get을 피할 수 있음을 알 수 있습니다.


While it's Ok to have different representations for different operations, a general recommendation for PUT is to contain the WHOLE payload. That means that id should be there as well. Otherwise, you should use PATCH.

Having said that, I think PUT should mostly be utilised for updates and the id should always be passed in the URL as well. As a result of that, using PUT to update the resource identifier is a bad idea. It leaves us in an undesirable situation when id in the URL can be different from the id in the body.

So, how do we resolve such a conflict? We basically have 2 options:

  • throw a 4XX exception
  • add a Warning(X-API-Warn etc) header.

That's as close as I can get to answering this question because the topic in general is a matter of opinion.


There is nothing bad in using different approaches. but i think the best way is the solution with 2nd.

 PUT /person/UUID {"name": "Jimmy"}

 GET /person/UUID returns {"id": <UUID>, "name": "Jimmy"}

it is mostly used in this way even the entity framework use this technique when the entity is added in dbContext the class without the generated ID is ID generated by reference in Entity Framework.


I'm looking at this from a JSON-LD/ Semantic Web point of view because that's a good way to go to achieve real REST conformance as I have outlined in these slides. Looking at it from that perspective, there is no question to go for option (1.) as the ID (IRI) of a Web resource should always be equal to the URL which I can use to look-up/ dereference the resource. I think the verification is not really hard to implement nor is it computationally intens; so I don't consider this a valid reason for going with option (2.). I think option (3.) is not really an option as POST (create new) has a different semantics than PUT (update/ replace).


You may need to look into PATCH/PUT request types.

PATCH requests are used to update a resource partially whereas in PUT requests, you have to send the entire resource where it gets overridden on the server.

As far as having an ID in the url is concerned, I think you should always have it as it is a standard practice to identify a resource. Even the Stripe API works that way.

You can use a PATCH request to update a resource on the server with ID to identify it but do not update the actual ID.

참고URL : https://stackoverflow.com/questions/27900041/rest-put-ids-in-body-or-not

반응형