RESTful API steht für das Fehlen einer Sache

18

Stellen Sie sich eine API vor, um festzustellen, ob eine Person ihr Geistestier ausgewählt hat. Sie können nur null oder ein Geister-Tier haben.

Zur Zeit:

/person/{id}/selectedSpiritAnimal

Wenn sie ein Tier ausgewählt haben, wird http 200 und zurückgegeben {selectedAnimal:mole}

Wenn sie jedoch keine Auswahl haben, wird http 404 zurückgegeben.

Dies macht mein Geister-Tier unglücklich, da wir ein gültiges Domain-Anliegen - das noch kein Geister-Tier ausgewählt hat - als HTTP-Fehler darstellen.

Außerdem möchten wir als Unternehmen - ähm Sprit-Animal-Hampers-R-us - wissen, wenn jemand keine Auswahl hat, damit wir ihn dazu auffordern können.

Was ist eine bessere Antwort hier:

HTTP 200 und {selectedAnimal:null}

oder noch expliziter

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

Oder ist es besser, einen 404 zurückzugeben? Da ähnlich wie this image has not yet been uploadedbeim Betrachten eines Bildes online ein 404 this person has not selected a spirit animalsein würde, könnte ein 404 sein


Diese Frage wurde als Duplikat vorgeschlagen, adressiert jedoch eine ansonsten gültige URL, die angefordert wird, wenn die Anwendung so konfiguriert wurde, dass die von dieser URL dargestellte Änderung nicht zulässig ist.

Während ich hier sehe, wie man eine Ressource darstellt, bei der das Fehlen der Ressource von Bedeutung ist. Dh es ist für den Kunden gültig, die URL anzufordern, und die Antwort lautet, dass Sie die Ressource erfolgreich angefordert haben, die das Fehlen einer Sache darstellt.

Das ist also keine "Geschäftslogik", sondern ein Umstand, in dem das Fehlen einer Sache eine Bedeutung hat (es kann sein, dass viele meiner Kollegen argumentieren, dass 404 immer noch korrekt ist), aber ich bin nicht sicher, wie ich das dem zuordnen soll spez.


Es ist sehr schwierig, eine Antwort zu finden. Ich habe es mir im Laufe des Gesprächs hier und auf der Arbeit mehrmals anders überlegt.

Die Sache, die es für mich hier regelt, ist, dass die Spezifikation sagt, dass ein 4xx ist, wenn der Kunde geirrt hat . In diesem Fall wurde der Client angewiesen, eine Antwort von der URL selectedSpiritAnimal zu erwarten, sodass kein Fehler aufgetreten ist.

Meine Kollegen sind sich einig, dass dies ein Symptom für ein schlechtes API-Design ist

Es ist wahrscheinlich besser, wenn wir einfach / person / {id} anfordern und eine Reihe von Verknüpfungsbeziehungen für die Person zurückgeben nenne es trotzdem dann macht ein 404 sinn. Oder Sie implementieren Teilantworten und lassen / person / {id} ein vollständigeres Dokument zurückgeben, sofern der Client keine Teilmenge der Daten anfordert

Paul D'Ambra
quelle
5
Sie haben nicht erklärt, warum Sie glauben, dass es ein Problem ist, eine 404 zurückzugeben. Aus Domain-Sicht wissen Sie nicht, ob Sie eine 404 oder eine 200 erhalten haben, die von der Client-Ebene abstrahiert wird.
Vincent Savard
14
oder vielleicht ist es besser, 204 no-content zurückzugeben?
Paul D'Ambra
6
Ich nehme an, meine Sorge mit 404 besteht darin, eine Konfigurationsänderung zu disambiguieren, die eine ungültige URL-Vorlage von einer Person ohne Geister-Tier einführt
Paul D'Ambra,
2
@ PaulD'Ambra Für das, was es wert ist, würde ich kein No-Content verwenden. Ich habe seit den Tagen von XmlHttpRequest keine HTTP-Codes im Front-End mehr gesehen, die auf diese Weise in Javascript gehandhabt wurden. Aber es ist sicherlich gültig.
Brandon Arnold

Antworten:

24

HTTP 4xx-Codes sind wahrscheinlich nicht die richtige Wahl für dieses Szenario. Sie geben an, dass es ein gültiger Status ist, Tiere mit null Geistern zu haben, und die API-Route person/{id}/selectedSpiritAnimalberücksichtigt, ob eine Person eines idhat oder nicht.

HTTP 4xx-Antworten sind für den Fall reserviert, dass ein Client in der Anforderung etwas Falsches getan hat (siehe Archiv der ursprünglichen Spezifikation von w3 ). Der Kunde macht jedoch eine gültige Anfrage, ob eine Person idein Geistertier hat oder nicht .

Daher neige ich zur zweiten Lösung, indem ich einen korrekt formatierten JSON-Body in der Antwort und einen HTTP-2xx-Code verwende.

Wenn Sie nun eine solche Anfrage erhalten und sich herausstellt, dass die Person idnicht existiert, ist ein 4xx-Code sinnvoller.

Brandon Arnold
quelle
17
Msgstr "HTTP 4xx - Antworten sind für den Fall reserviert, dass ein Client in der Anfrage etwas Falsches getan hat". Wenn Sie maßgebliche Aussagen zur Spezifikation machen, beziehen Sie sich bitte auf die tatsächliche HTTP-Spezifikation und nicht auf (a) ein darauf aufgebautes Framework oder (b) einen zufälligen Blog-Beitrag.
Eric Stein
5
@ EricStein Ich fühlte mich ein bisschen faul dabei; Danke für die Kritik. Aktualisiert.
Brandon Arnold
1
Ich denke, der RFC-Link hier ist widersprüchlich. Einerseits sagt der 4xx Teil cases in which the client seems to have erred, andererseits sagt der 404 direkt The server has not found anything matching the Request-URI. Sie könnten in Betracht ziehen, etwas anzufordern, das keinen Clientfehler enthält. Ich verstehe die Person, die nicht existiert, im Vergleich zu einer nicht existierenden Sub-Requisite, aber das könnte als Antwortnachricht angezeigt werden. 204 scheint ebenfalls relevant zu sein, da die Entität existiert, aber keinen Inhalt für eine Sub-Eigenschaft hat.
Shortstuffsushi
1
Der Kunde hat etwas falsch gemacht; es hat das ausgewählte Geistestier für einen Benutzer angefordert, wenn es nicht existiert. Genau das bedeutet 404 ... Sie haben nach etwas gefragt, das nicht da ist.
Andy
5
Wenn mein Browser eine Anfrage an softwareengineering.stackexchange.com/questions/unicorn stellt, ist die Anfrage gültig, und dennoch erhalte ich eine 404 (es gibt zufällig keine Frage mit der ID "Unicorn").
user253751
24

Lassen Sie mich Ihnen das Richardson Maturity Model vorstellen .

Ihr Problem ist, dass Sie zwei Ressourcen als eine darstellen, wobei Sie eigentlich zwei Ressourcen haben sollten, deren Beziehung durch Hypermedia angegeben ist. Das Verwenden von Hypermedien zur Beschreibung von Beziehungen ist die glorreiche Ebene 3 von Rest.

Ihre Person sollte unter der URI leben /person/{id}und das Tier sollte unter der URI leben /spiritanimal/{id}. Die Person sollte durch einen Link zum Tier angeben, dass sie ein Geistestier hat.

Stellen wir uns eine Person namens Bob vor, die die ID 123 und ein Einhorn-Geistertier hat.

GET /person/123

würden zurückkehren;

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

Jetzt weiß jeder, der Person 123 liest, dass er ein Geistertier hat und die URI hat, unter der er weitere Informationen dazu erhalten kann.

GET /spitiranimal/789

könnte zurückkehren

{
  "type": "Unicorn"
}

Stellen wir uns nun eine Person namens Fred vor, die die ID 456 hat und kein Geistertier.

GET /person/456

würden zurückkehren;

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

Jetzt wird jeder, der Person 456 liest, wissen, dass er kein Geistestier hat, da es keine Verbindung gibt. Es ist nicht erforderlich, einen HTTP-Statuscode zu verwenden, um das Fehlen einer Beziehung darzustellen.

Qwerky
quelle
1
Fügte nur die Frage hinzu, dass angesichts der Möglichkeit, die API zu ändern, ein gewisses Maß an HATEOAS wahrscheinlich die richtige Lösung wäre. Das ist ein großartiges Beispiel dafür
Paul D'Ambra
1

Dies ist die geeignete URL, um Geistertiere zu bekommen. Daher ist ein 404-Fehler ungeeignet. 404 steht für ein technisches Problem, nicht für ein logisches Problem.

Die geeignete Lösung ist die Rückgabe von http 200 und {"selectedAnimal": null}

Sie sollen einen haben separaten Webmethod /person/{id}/hasSelectedSpiritAnimaldie zurückgibt {"isSpiritAnimalSelected": false}. Hinter den Kulissen kann es vorkommen, dass dieselben Methodenaufrufe ausgeführt werden oder nicht, wobei nur false zurückgegeben wird, wenn null, aber es liegt an der Entscheidung, nicht an dem verbrauchenden Code.

Es ist besser zu vermeiden, Abfragen ohne zwingenden Grund zu kombinieren, um sie in eine Webmethode zu unterteilen, selbst wenn die Abfragen eng miteinander verbunden sind.

TheCatWhisperer
quelle
1
Können Sie erklären, warum Sie glauben, dass dies die richtige Lösung ist? Ich kann das Zurücksenden von Daten nicht nachvollziehen, wenn keine Daten zurückgesendet werden müssen. Ich stimme Ihnen zu, dass ein 404 keinen Sinn ergibt, da die URL in Ordnung ist. Ein 204 scheint mir am sinnvollsten zu sein.
Vincent Savard
2
@VincentSavard-Statuscodes sind schwieriger zu verarbeiten als JSON-Antworten und eignen sich eher für technische Probleme als für die Übermittlung von Domaininformationen.
TheCatWhisperer
2
204: Kein Inhalt mit einem leeren Körper. Es ist alles klar und selbsterklärend. Keine Notwendigkeit, weiter zu streiten. Alles in allem, wenn es kein klares Entwurfsmuster gibt, sollte eine SE eines auswählen, es an ihre Bedürfnisse anpassen und Dokumentation bereitstellen. Die Rückgabe eines Körpers mit einer Antwort von 204 ist nicht konsequent.
Formixian
2
@formixian ... Wenn Sie eine bjson / tcp-API anstelle einer json / http erstellen würden, was würden Sie für diesen Fall zurückgeben? Das Verlassen auf http-Codes scheint mir die Ergebnisse der API unnötig an die http-Implementierung zu binden.
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"Kein Inhalt bedeutet kein Inhalt . dh: es gibt "" zurück. Diese beiden sind überhaupt nicht ähnlich. "Das Geistertier ist derzeit nicht in der Akte" unterscheidet sich stark von "".
Shane
1

Was Ihr Endpunkt darstellt, ist nicht nur ein Tier. Es ist ein Tier oder ein Mangel daran. Es ist ein Wert, der am besten durch ein Optional/ Maybe/ Nullable/ usw. dargestellt wird.

So legitime Werte (wie in 200 OK) können sein:

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

Ich könnte mir vorstellen, dass die DELETEMethode, wenn sie auf den Endpunkt angewendet wird 'selected', falseerneut festgelegt werden kann, das heißt, das ausgewählte Tier wird nicht festgelegt.

Sie können den 'selected'Schlüssel natürlich hier ablegen, er wird nur zur Verdeutlichung angezeigt. Zeichenfolge vs nullist genug für die Unterscheidung.

9000
quelle
0

Sie sollten 404 verwenden.

Der Statuscode 404 (Nicht gefunden) gibt an, dass der Ursprungsserver keine aktuelle Darstellung für die Zielressource gefunden hat

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

Da Sie eine Programmierschnittstelle und keine Benutzerschnittstelle erstellen, ist der Text 404 optional.

Ich bevorzuge dies, weil ich Standardprotokolle so oft wie möglich bevorzuge. HTTP hat eine Möglichkeit, Nichtexistenz darzustellen, und das würde ich verwenden.

BEARBEITEN: Angenommen, Sie haben eine Funktion hinzugefügt, mit der Benutzer auswählen können, ob ihre Geistertiere geteilt werden sollen, und jemand hat sie nicht geteilt. Würden Sie 200 OK nulloder 200 OK zurückgeben "Unauthorized? Oder würden Sie den Standard 401 Unauthorized / 403 Forbidden verwenden? Dies scheint direkt analog zu sein, als würde man sich überhaupt nicht für eine entscheiden.


Wenn Sie alternativ 200 OK + JSON verwenden möchten, sollten Sie zurückkehren 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

Halte die Dinge sauber. Erstellen Sie nur bei Bedarf weitere Umhüllungen.

Paul Draper
quelle
2
Die Daten werden jedoch gefunden. Es kommt nur vor, dass die Daten null(keinen Wert haben). Dies unterscheidet sich davon, dass der Client etwas anfordert, für das kein Steckplatz für den Wert vorhanden ist. Sie würden nicht vorschlagen, ein AttributeErrorin Python zu werfen, wenn der Wert zufällig ist None; das würde die Schnittstelle unpraktisch und unnötig schwierig machen, mit zu arbeiten. Noch pragmatischer ist, dass viele HTTP-Client-APIs den 404 in den Standard-Fehlerbehandlungsmechanismus der Sprache (Fehlercode, Ausnahme, Fehlertyp) umwandeln, was bedeutet, dass Sie einen überflüssigen Fehler unterdrücken müssen.
jpmc26
@Paul Draper Scrollen Sie ein wenig in der Spezifikation nach oben, und Sie werden sehen, dass eine pauschale Aussage über HTTP 4xx gemacht wird: "Die Statuscode-Klasse 4xx ist für Fälle gedacht, in denen der Client fehlerhaft zu sein scheint." Die Operation hat klargestellt, dass es ein gültiger Zustand ist, für den die API verantwortlich sein sollte, kein Geistestier zu haben. tools.ietf.org/html/rfc7231#section-6.5
Brandon Arnold
Wie Sie das tun, dann unterscheiden zwischen der Nicht-Existenz der angeforderten Ressource angibt (dh kein Tier ausgewählt) und Client einen ungültigen Pfad anfordert (dh /person/{id}/selectedSpritAnimal, beachten Sie die Tippfehler in Sprit).
Sampathsris
1
Unabhängig von der Absicht bedeutet ein 404, dass die Ressource nicht gefunden wurde. Wenn ein selectedSpiritAnimal eine Ressource ist und keine vorhanden ist, gibt es nichts zu holen und eine 404 ist angemessen. Wenn der Client jedoch wissen möchte, ob ein Geistertier ausgewählt wurde, sollte der Server eine andere Ressource /person/{id}/isSpiritAnimalSelectedverfügbar machen, die dem Client mitteilt, ob eine ausgewählt wurde. Scheint mir das gleiche klassische Beispiel zu sein, bei dem vor dem Lesen geprüft wird, ob eine Datei vorhanden ist. Lesen Sie einfach die Datei und behandeln Sie den ENOENT-Fehler, falls er ausgelöst werden sollte.
Aaaaaa
1
@PaulDraper Es geht nicht darum, ob die Ressource existiert oder nicht. Der Punkt ist, dass HTTP 4xx-Codes für den Fall bestimmt sind, dass der Aufrufer die API falsch verwendet. Op gibt an, dass /person/{id}/selectedSpiritAnimalverwendet werden soll, auch wenn es kein geistiges Tier gibt. Dies bedeutet, dass HTTP 4xx in einem solchen Fall nicht korrekt ist. Op gibt auch korrekt an, dass dies ein Geruch von schlechtem API-Design sein kann.
Brandon Arnold