RESTful API는 사물의 부재를 나타냅니다.


18

사람이 자신의 정신 동물을 선택했는지 식별하는 API를 상상해보십시오. 그들은 영의 동물을 하나만 가질 수 있습니다.

현재 :

/person/{id}/selectedSpiritAnimal

그들이 동물을 선택하면 http 200을 반환하고 {selectedAnimal:mole}

그러나 선택이 없으면 http 404를 반환합니다.

이것은 우리가 유효한 도메인 관심사 (아직 정령 동물을 선택하지 않은)를 HTTP 오류로 나타내면서 나의 정령 동물을 불행하게 만듭니다.

또한 비즈니스 인 Sprit-Animal-Hampers-R-us로서 우리는 누군가가 선택을 할 수 없는지 알고 싶어하므로 프롬프트를 표시 할 수 있습니다.

더 나은 답변은 다음과 같습니다.

HTTP 200과 {selectedAnimal:null}

또는 더 명백한

HTTP 200과 {selectedAnimal:null, spiritAnimalSelected: false}

아니면 404를 반환하는 것이 낫습니까? this image has not yet been uploaded온라인에서 이미지를 볼 때 와 마찬가지로 404 this person has not selected a spirit animal일 것이므로 404 일 수 있습니다.


이 질문 은 중복으로 제안되었지만 해당 질문은 URL이 나타내는 변경을 허용하지 않도록 응용 프로그램을 구성했을 때 요청되는 유효한 URL을 처리합니다.

여기에서는 리소스가없는 의미가있는 리소스를 나타내는 방법을 살펴 봅니다. 즉, 클라이언트가 URL을 요청하는 것이 유효하며 응답은 사물이 없음을 나타내는 리소스를 성공적으로 요청한 것입니다.

따라서 이것은 '비즈니스 로직'이 아니라 사물의 부재가 의미가있는 상황입니다 (404는 여전히 옳다고 주장하는 많은 동료가있을 수 있습니다). 투기.


답을 고르기가 매우 어렵습니다. 나는 대화와 직장에서 진행되는 대화에 대해 여러 번 생각을 바 꾸었습니다.

나를 위해 여기에 정착하는 것은 4xx는 클라이언트가 오류가 발생했을 때 입니다. 이 경우 클라이언트는 selectedSpiritAnimal url의 응답을 예상해야하므로 오류가 발생하지 않았습니다.

내 동료들 사이의 합의는 이것이 잘못된 API 디자인의 증상이라는 것입니다.

우리는 단순히 / person / {id}를 요청하고 그 사람에 대한 일련의 링크 관계를 반환하는 것이 더 나을 것입니다 ... 그런 다음 / selectedSpiritAnimal 링크가 주어지지 않으면 (사람이 선택하지 않은 경우) 어쨌든 그것을 호출하면 404가 의미가 있습니다. 또는 부분 응답을 구현하고 클라이언트가 데이터의 서브 세트를 요청하지 않는 한 / person / {id}가 더 완전한 문서를 리턴하도록합니다.


5
404를 반환하는 것이 문제라고 생각하는 이유를 설명하지 않았습니다. 도메인 관점에서 클라이언트 계층에 의해 추상화 된 404 또는 200을 받았는지 알 수 없습니다.
Vincent Savard

14
또는 204 no-content를 반환하는 것이 더 낫습니까?
Paul D' Ambra

6
404에 대한 걱정이 스피릿 동물이없는 사람으로부터 잘못된 URL 템플릿을 도입하는 구성 변경을 명확하게하는 것으로 생각합니다.
Paul D' Ambra

2
@ PaulD'Ambra 그만한 가치가 있다면, 나는 아무 내용도 사용하지 않을 것입니다. XmlHttpRequest 이후로 Javascript에서 프론트 엔드에서 HTTP 코드가 처리되는 것을 보지 못했습니다. 그러나 확실히 유효합니다.
Brandon Arnold

답변:


24

HTTP 4xx 코드는이 시나리오에서 올바른 선택이 아닙니다. 영의 동물이없는 상태는 유효한 상태이며 API 경로 person/{id}/selectedSpiritAnimal는 사람 id이 없는지 여부를 설명합니다 .

HTTP 4xx 응답은 클라이언트가 요청에서 잘못된 작업을 수행 한 상황을 위해 예약되어 있습니다 ( 원래 사양의 w3의 아카이브 참조 ). 그러나 고객은 사람 id이 정신 동물을 가지고 있는지 여부에 관계없이 유효한 요청을하고 있습니다.

따라서 응답에 올바른 형식의 JSON 본문과 HTTP 2xx 코드를 사용하여 두 번째 솔루션에 의존합니다.

이제 그러한 요청을 받고 사람 id이 존재하지 않는 것으로 밝혀지면 4xx 코드가 더 합리적입니다.


17
"HTTP 4xx 응답은 클라이언트가 요청에서 잘못된 작업을 수행 한 상황을 위해 예약되어 있습니다." 사양에 대한 권위있는 진술을 할 때는 (a) 위에 구축 된 프레임 워크 또는 (b) 임의의 블로그 게시물이 아니라 실제 HTTP 사양을 참조하십시오.
Eric Stein

5
@EricStein 나는 그것에 대해 약간 게으름을 느꼈다. 비평 주셔서 감사합니다. 업데이트되었습니다.
Brandon Arnold

1
여기 RFC 링크가 충돌하는 것 같습니다. 한편으로는 4xx 부분이 cases in which the client seems to have erred있지만 다른 한편으로는 404가 직접 말합니다 The server has not found anything matching the Request-URI. 클라이언트 오류가없는 것을 요청하는 것을 고려할 수 있습니다. 존재하지 않는 사람과 존재하지 않는 하위 소품을 이해하지만 응답 메시지로 표시 될 수 있습니다. 204 개체도 존재하지만 하위 속성에 대한 내용이 없기 때문에 관련성이있는 것 같습니다.
shortstuffsushi

1
클라이언트가 잘못된 일을했다. 존재하지 않을 때 사용자에게 선택된 스피릿 동물을 요청했습니다. 정확히 404의 의미입니다 ... 당신은 거기에없는 것을 요구했습니다.
Andy

5
브라우저가 softwareengineering.stackexchange.com/questions/unicorn에 요청 하면 유효한 요청이지만 여전히 404를 얻습니다 (ID "unicorn"에 대해서는 의문의 여지가 없습니다).
user253751

24

Richardson Maturity Model 을 소개하겠습니다 .

문제는 두 개의 리소스를 하나로 표현한다는 것인데, 실제로 하이퍼 미디어로 표시되는 관계가있는 두 개의 리소스가 있어야합니다. 관계를 설명하기 위해 하이퍼 미디어를 사용하는 것이 영광스러운 휴식 레벨 3입니다.

귀하의 사람은 URI 아래에 /person/{id}살고 동물은 아래에 있어야합니다 /spiritanimal/{id}. 사람은 동물과의 링크를 사용하여 정신 동물을 가지고 있음을 표시해야합니다.

ID가 123이고 유니콘 정신 동물을 가진 Bob이라는 사람을 상상해 봅시다.

GET /person/123

돌아올 것이다;

{
  "name": "Bob",
  "links": [
    {
      "rel": "spiritanimal",
      "uri": "/spiritanimals/789"
    }
  ]
}

이제 사람 123을 읽는 사람이라면 누구나 정신 동물이 있고 더 많은 정보를 얻을 수있는 URI가 있다는 것을 알게 될 것입니다.

GET /spitiranimal/789

돌아올지도 모른다

{
  "type": "Unicorn"
}

이제 ID가 456이고 영 동물이없는 Fred라는 사람을 상상해보십시오.

GET /person/456

돌아올 것이다;

{
  "name": "Fred",
  "links": [
  ]
}

이제 사람 456을 읽는 사람은 링크가 없기 때문에 영 동물이 없다는 것을 알게 될 것입니다. 관계가 없음을 나타 내기 위해 HTTP 상태 코드를 사용할 필요가 없습니다.


1
API를 변경할 수있는 능력이 주어지면 HATEOAS의 일부 수준이 아마도 올바른 해결책 일 것입니다. 그 좋은 예입니다
Paul D' Ambra

1

이것은 정신 동물을 얻는 데 적합한 URL입니다. 따라서 404 오류는 부적절합니다. 404는 논리 문제가 아닌 기술 문제를 나타냅니다.

적절한 해결책은 http 200을 반환하고 {"selectedAnimal": null}

를 반환 하는 별도의 웹 메소드 가 있어야 /person/{id}/hasSelectedSpiritAnimal합니다 {"isSpiritAnimalSelected": false}. 장면 뒤에서 동일한 메소드 호출을 수행하거나 수행하지 않을 수 있습니다. null 인 경우 false를 반환하지만 소비 코드가 아닌 결정하기에 달려 있습니다.

쿼리가 밀접하게 관련되어 있더라도 강력한 이유없이 쿼리를 하나의 웹 메서드로 분리하는 것을 피하는 것이 좋습니다.


1
이것이 적절한 해결책이라고 생각하는 이유를 설명해 주시겠습니까? 반환 할 데이터가 없을 때 데이터를 반환한다는 의미는 없습니다. URL이 좋기 때문에 404가 의미가 없으므로 204가 나에게 가장 의미가있는 것 같습니다.
Vincent Savard

2
@VincentSavard 상태 코드는 json 응답보다 작동하기가 어렵고 도메인 정보를 전달하는 대신 기술적 인 문제에 더 적합합니다.
TheCatWhisperer

2
204 : 본문이 비어있는 콘텐츠없습니다 . 그것은 모두 명확하고 자명하다. 더 이상 논쟁 할 필요가 없습니다. 결국, 명확한 디자인 패턴이없는 경우 SE는 하나를 선택하여 필요에 맞게 구부려 문서를 제공해야합니다. 204 응답의 본문을 반환하는 것은 결과가 아닙니다.
formixian

2
@formixian ... json / http 대신 bjson / tcp API를 작성하는 경우이 경우 어떤 결과를 반환합니까? http 코드에 의존하는 것은 API의 결과를 불필요하게 http 구현에 바인딩하는 것 같습니다.
TheCatWhisperer

2
@VincentSavard When you said "the spirit animal is not currently on file", it seemed quite similar to me to "there is no content"내용 없음은 내용이 없음을 의미 합니다 . 즉, ""를 반환합니다. 이 두 가지는 전혀 비슷하지 않습니다. "정령 동물이 현재 파일에 없습니다"는 ""와는 매우 다릅니다.
셰인

1

엔드 포인트가 나타내는 것은 단순한 동물이 아닙니다. 그것은 동물이거나 그것의 부족입니다. Optional/ Maybe/ Nullable/ 등으로 가장 잘 표현되는 값입니다 .

따라서 합법적 인 값 (200 OK와 같이)은 다음과 같습니다.

  • {'animal': <some animal>, 'selected': true}
  • {'animal': null, 'selected': false}

내가 그 상상할 수있는 DELETE엔드 포인트에 적용 할 때 방법을 설정할 수 있습니다 'selected'false즉, 선택된 동물을 설정 해제, 다시.

물론 'selected'여기에 키를 놓을 수 있습니다 . 명확성을 위해서만 표시됩니다. 문자열 대 null충분합니다.


0

404를 사용해야합니다.

404 (찾을 수 없음) 상태 코드는 오리진 서버가 대상 자원에 대한 현재 표시를 찾지 못했음을 나타냅니다.

RFC7231

HTTP/1.1 200 OK
Content-Type: application/json
Date: Mon, 25 Sep 2017 00:00:00 GMT

"mole"

HTTP/1.1 404 Not Found
Content-Type: text/plain
Date: Mon, 25 Sep 2017 00:00:00 GMT

this person has not selected a spirit animal

휴먼 인터페이스가 아닌 프로그래밍 인터페이스를 작성하므로 404 텍스트는 선택 사항입니다.

가능한 한 표준 프로토콜을 선호하기 때문에 이것을 선호합니다. HTTP에는 존재하지 않는 것을 나타내는 방법이 있으며 이것이 내가 사용하는 것입니다.

편집 : 사용자가 그들의 정신 동물을 공유할지 여부를 선택할 수있는 기능을 추가했다고 가정하고 누군가가 그것을 공유하지 않았다고 가정 해보십시오. 200 OK null또는 200 OK 를 반환 하시겠습니까 "Unauthorized? 아니면 표준 401 Unauthorized / 403 Forbidden을 사용 하시겠습니까? 이것은 처음에 하나를 선택하지 않는 것과 직접적으로 유사합니다.


또는 200 OK + JSON을 사용하려면을 반환해야합니다 null.

HTTP/1.1 200 OK
Content-Type: application/json
Date: Mon, 25 Sep 2017 00:00:00 GMT

"mole"

HTTP/1.1 200 OK
Content-Type: application/json
Date: Mon, 25 Sep 2017 00:00:00 GMT

null

물건을 깨끗하게 유지하십시오. 필요한 경우에만 더 많은 줄 바꿈을 작성하십시오.


2
그러나 데이터 발견되었습니다. 데이터가 null(값이 없음) 발생합니다. 이는 값을 보유 할 슬롯이없는 것을 요청하는 클라이언트와 다릅니다. AttributeError값이 발생할 때 파이썬에서 던지기를 제안하지 않습니다 None. 인터페이스가 실용적이지 않고 불필요하게 작업하기가 어렵습니다. 더 실용적으로, 많은 HTTP 클라이언트 API는 404를 언어의 표준 오류 처리 메커니즘 (오류 코드, 예외, 오류 유형)으로 변환 할 수 있습니다. 즉, 외부 오류를 억제해야합니다.
jpmc26

@Paul Draper 스펙에서 약간 위로 스크롤하면 HTTP 4xx에 대한 포괄적 인 설명을 볼 수 있습니다. "4xx 등급의 상태 코드는 클라이언트가 오류가 발생한 경우를위한 것입니다." OP는 정신 동물을 갖지 않는 것이 API가 설명해야하는 유효한 상태라고 분명히 밝혔습니다. tools.ietf.org/html/rfc7231#section-6.5
Brandon Arnold

그러면 요청 된 자원이 존재하지 않음 (즉, 동물이 선택되지 않음)을 표시하는 클라이언트와 유효하지 않은 경로를 요청하는 클라이언트 (즉 /person/{id}/selectedSpritAnimal, 오타를 관찰 )를 구별하는 방법은 무엇입니까 Sprit?
sampathsris

1
의도와 상관없이 404는 리소스를 찾을 수 없다는 것을 의미합니다. selectedSpiritAnimal이 자원이고 존재하지 않는 경우 GET에 아무것도 없으며 404가 적합합니다. 그러나 클라이언트가 스피릿 동물이 선택되었는지 여부를 알고 싶다면 서버는 /person/{id}/isSpiritAnimalSelected클라이언트가 선택되었는지 여부를 알려주는 다른 리소스 를 노출해야합니다 . 파일을 읽기 전에 파일이 존재하는지 테스트하는 것과 동일한 고전적인 예를 보았습니다. 파일을 읽고 ENOENT 오류를 처리하십시오.
aaaaaa

1
@PaulDraper 요점은 리소스가 존재하는지 여부입니다. 요점은 HTTP 4xx 코드는 호출자가 API를 잘못 사용하는 경우를위한 것입니다. /person/{id}/selectedSpiritAnimal영 동물이 존재하지 않더라도 사용되도록되어있는 Op 상태 . 이는 그러한 경우에 사용될 때 HTTP 4xx가 올바르지 않음을 의미합니다. Op는 또한 이것이 잘못된 API 디자인 냄새 일 수 있음을 올바르게 나타냅니다.
Brandon Arnold
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.