REST-HTTP-Statuscodes für fehlgeschlagene Validierung oder ungültiges Duplikat

826

Ich erstelle eine Anwendung mit einer REST-basierten API und bin an einem Punkt angelangt, an dem ich Statuscodes für jede Anforderung spezifiziere.

Welchen Statuscode sollte ich für Anfragen senden, bei denen die Validierung fehlschlägt oder bei denen eine Anfrage versucht, ein Duplikat in meine Datenbank aufzunehmen?

Ich habe http://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html durchgesehen, aber keiner von ihnen scheint richtig zu sein.

Gibt es eine gängige Praxis beim Senden von Statuscodes?

alexn
quelle

Antworten:

780

Bei Fehler bei der Eingabevalidierung: 400 Bad Request + Ihre optionale Beschreibung. Dies wird im Buch " RESTful Web Services " vorgeschlagen. Für doppelte Einreichung: 409 Konflikt


Update Juni 2014

Die relevante Spezifikation war früher RFC2616 , was die Verwendung von 400 (Bad Request) eher eng als

Die Anforderung konnte vom Server aufgrund einer fehlerhaften Syntax nicht verstanden werden

Es könnte also argumentiert worden sein, dass es für semantische Fehler ungeeignet war. Aber nicht mehr; Seit Juni 2014 sieht der relevante Standard RFC 7231 , der den vorherigen RFC2616 ersetzt, die Verwendung von 400 (Bad Request) im weiteren Sinne vor

Der Server kann oder wird die Anforderung nicht verarbeiten, da dies als Clientfehler angesehen wird

Deamon
quelle
3
Ja, der Anforderungshauptteil ist Teil der Syntax.
Deamon
62
Eine schlechte Anfrage ist definitiv die häufigste Antwort auf diese Art von Problem. Die einzige andere Alternative ist 422 Unprocessable Entity. Es stammt tatsächlich von WebDav, ist jedoch vollkommen gültig, um jeden bei IANA registrierten Statuscode wiederzuverwenden.
Darrel Miller
19
Wie unterscheiden Sie also zwischen fehlerhaften Daten, die der Server nicht einmal analysieren kann, und einem Validierungsfehler? Ein Kunde würde diese beiden Antworten völlig unterschiedlich behandeln. Zur Validierung würden sie dem Benutzer wahrscheinlich die Fehler anzeigen. Bei wirklich "fehlerhaften Daten" würden sie den Fehler protokollieren, damit der Fehler in der Methode, die die Anforderung generiert, behoben werden kann.
Josh Noe
18
Ich bin mit Ihrer Interpretation von RFC7231 nicht einverstanden, obwohl darin angegeben ist something perceived to be a client error, dass alle in diesem Absatz aufgeführten Beispiele Verstöße gegen das HTTP-Protokoll und keine logischen Fehler sind: Syntax, Framing, Routing. Daher bin ich der Meinung, dass die HTTP-Spezifikation 400 für eine fehlgeschlagene Validierung auf Anwendungsebene nicht zulässt.
Dima Tisnek
2
Warum nicht eine 422 - Nicht verarbeitbare Entität verwenden? Scheint mir logischer
java_geek
278
  • Fehlgeschlagene Validierung: 403 Verboten ("Der Server hat die Anforderung verstanden, weigert sich jedoch, sie zu erfüllen"). Entgegen der landläufigen Meinung sagt RFC2616 nicht "403 ist nur für fehlgeschlagene Authentifizierung vorgesehen", sondern "403: Ich weiß, was Sie wollen, aber das werde ich nicht tun". Diese Bedingung kann auf eine Authentifizierung zurückzuführen sein oder nicht.
  • Versuch, ein Duplikat hinzuzufügen: 409 Konflikt ("Die Anforderung konnte aufgrund eines Konflikts mit dem aktuellen Status der Ressource nicht abgeschlossen werden.")

Sie sollten auf jeden Fall eine detailliertere Erklärung in den Antwortheadern und / oder im Text geben (z. B. mit einem benutzerdefinierten Header - X-Status-Reason: Validation failed).

Piskvor verließ das Gebäude
quelle
17
@deamon: Das ist nicht die Spezifikation, das ist Wikipedia, dh die Meinung von jemandem zu "was HTTP-Statuscodes bedeuten"; Beachten Sie, dass auf der Seite im Wesentlichen "Dies ist, was Apache mit 403 bedeutet, dies ist, was IIS mit 403 bedeutet" und nirgends auf den offiziellen RFC verwiesen wird. Sie scheinen zu wiederholen "403 bedeutet, was auch immer Apache sagt". NICHT. Der eigentliche RFC (das relevante Dokument, nicht die Implementierung von Apache, nicht die Implementierung von IIS, nicht die Implementierung eines anderen) ist hier: w3.org/Protocols/rfc2616/rfc2616-sec10.html
Piskvor hat das Gebäude
57
"10.4.4 403 Verboten Der Server hat die Anfrage verstanden, weigert sich jedoch, sie zu erfüllen. Die Autorisierung hilft nicht und die Anfrage sollte nicht wiederholt werden. Wenn die Anforderungsmethode nicht HEAD war und der Server veröffentlichen möchte, warum die Anfrage dies nicht getan hat erfüllt ist, SOLLTE es den Grund für die Ablehnung in der Entität beschreiben. Wenn der Server diese Informationen dem Client nicht zur Verfügung stellen möchte, kann stattdessen der Statuscode 404 (Nicht gefunden) verwendet werden. " Ich sehe dort keine Hervorhebung ("SOLLTE / SOLLTE NICHT" sind RFC 2119-Schlüsselwörter, keine Hervorhebung); Das ist Ihre Idee, was "verboten" bedeutet, nicht RFCs.
Piskvor verließ das Gebäude
10
Ich mag diese Antwort, sehe aber immer noch ein kleines Problem. Gemäß der Spezifikation sollte "die Anforderung NICHT wiederholt werden , wenn ein 403 zurückgegeben wird". Die Rückgabe eines 409 "ist jedoch nur in Situationen zulässig, in denen erwartet wird, dass der Benutzer den Konflikt möglicherweise lösen und die Anforderung erneut senden kann". Im Falle eines Duplikats halte ich 403 für angemessener, da Sie den Konflikt nicht wirklich lösen können (außer durch Löschen der vorherigen Instanz der Ressource).
Pablobm
2
Für die Fehlermeldung selbst sollten Sie den Grundsatz ändern, sodass das Senden des Headers HTTP/1.0 403 Form validation errorsder sauberste Weg ist.
Aleemb
6
IMO, 422 "Unprocessable Entity" macht viel mehr Sinn. Meine Argumentation ist, dass der Server sich nicht weigert , eine Anfrage zu erfüllen, sondern dass der Server die Anfrage nicht erfüllen kann.
Tybro0103
225

Ich empfehle den Statuscode 422 "Nicht verarbeitbare Entität" .

11.2. 422 Nicht verarbeitbare Entität

Der Statuscode 422 (nicht verarbeitbare Entität) bedeutet, dass der Server den Inhaltstyp der Anforderungsentität versteht (daher ist ein 415-Statuscode (nicht unterstützter Medientyp) unangemessen) und die Syntax der Anforderungsentität korrekt ist (daher eine 400 (fehlerhafte Anforderung) ) Statuscode ist unangemessen) konnte die enthaltenen Anweisungen jedoch nicht verarbeiten. Diese Fehlerbedingung kann beispielsweise auftreten, wenn ein XML-Anforderungshauptteil wohlgeformte (dh syntaktisch korrekte), aber semantisch fehlerhafte XML-Anweisungen enthält.

Julian Reschke
quelle
11
Natürlich handelt es sich um einen HTTP-Statuscode, siehe iana.org/assignments/http-status-codes . Es gibt mehr Statuscodes als in RFC 2616 definiert.
Julian Reschke
7
WebDAV ist eine HTTP- Erweiterung . "HTTP-Erweiterungen für Web Distributed Authoring und Versionierung (WebDAV)" Der Statuscode 422 ist also kein http-Statuscode, sondern ein Statuscode einer Erweiterung von http.
Deamon
16
Deamon, das macht keinen Sinn. HTTP definiert, wie neue Codes definiert werden, und genau das tut WebDAV. Es gibt eine Statuscode-Registrierung aus einem bestimmten Grund.
Julian Reschke
14
FYI - RFC-Beschreibung von 422: 11.2. 422 Nicht verarbeitbare Entität Der Statuscode 422 (Nicht verarbeitbare Entität) bedeutet, dass der Server den Inhaltstyp der Anforderungsentität versteht (daher ist ein 415-Statuscode (nicht unterstützter Medientyp) unangemessen) und die Syntax der Anforderungsentität korrekt ist (daher 400) Der Statuscode (Bad Request) ist unangemessen.) Die enthaltenen Anweisungen konnten jedoch nicht verarbeitet werden. Diese Fehlerbedingung kann beispielsweise auftreten, wenn ein XML-Anforderungshauptteil wohlgeformte (dh syntaktisch korrekte), aber semantisch fehlerhafte XML-Anweisungen enthält.
Steve Kallestad
6
Und Threads verfallen nicht. Sie müssen am Leben bleiben, sonst werden die Top-Google-Suchergebnisse ungenau.
James Billingham
81

200.300, 400, 500 sind alle sehr allgemein. Wenn Sie generisch möchten, ist 400 in Ordnung.

422 wird von einer zunehmenden Anzahl von APIs verwendet und wird sogar von Rails sofort verwendet.

Unabhängig davon, welchen Statuscode Sie für Ihre API auswählen, wird jemand anderer Meinung sein. Aber ich bevorzuge 422, weil ich den '400 + Textstatus' für zu allgemein halte. Außerdem nutzen Sie keinen JSON-fähigen Parser. Im Gegensatz dazu ist ein 422 mit einer JSON-Antwort sehr explizit und es können viele Fehlerinformationen übermittelt werden.

Apropos JSON-Antwort: Ich tendiere dazu, die Rails-Fehlerantwort für diesen Fall zu standardisieren:

{
    "errors" :
    { 
        "arg1" : ["error msg 1", "error msg 2", ...]
        "arg2" : ["error msg 1", "error msg 2", ...]
    }
}

Dieses Format eignet sich perfekt für die Formularvalidierung, die meiner Meinung nach der komplexeste Fall ist, der im Hinblick auf die Fülle von Fehlerberichten unterstützt wird. Wenn Ihre Fehlerstruktur so ist, werden wahrscheinlich alle Ihre Fehlerberichterstattungsanforderungen erfüllt.

Sethcall
quelle
2
Was ist mit Fehlern, die sich aus Interaktionen zwischen den Argumenten ergeben? Das heißt, arg1ist gültig und arg2gültig, aber die Kombination der beiden mit den spezifischen gesendeten Werten ist nicht gültig.
Jonah
1
Ich würde es nicht überdenken. Wählen Sie einfach eine aus, die die Beziehung zu besitzen scheint.
Sethcall
oder auch nur ein Fehler bei beiden Argumenten. Als Benutzer möchte ich den Fehler in jedem der widersprüchlichen Felder sehen, denke ich.
kuschelt sich
Nett!. explizit ist besser als implizit
bhathiya-perera
46

200

Ugh ... (309, 400, 403, 409, 415, 422) ... viele Antworten, die versuchen, den besten Rückkehrcode für eine erfolgreiche HTTP-Anforderung, aber einen fehlgeschlagenen REST-Aufruf zu erraten, zu argumentieren und zu standardisieren .

Es ist falsch , HTTP-Statuscodes und REST-Statuscodes zu mischen.

Ich habe jedoch viele Implementierungen gesehen, die sie gemischt haben, und viele Entwickler stimmen mir möglicherweise nicht zu.

HTTP-Rückkehrcodes beziehen sich auf sich HTTP Requestselbst. Ein REST-Aufruf wird mithilfe einer Hypertext Transfer Protocol-Anforderung ausgeführt und arbeitet auf einer niedrigeren Ebene als die aufgerufene REST-Methode selbst. REST ist ein Konzept / Ansatz, und seine Ausgabe ist ein geschäftliches / logisches Ergebnis, während der HTTP-Ergebniscode ein Transportergebnis ist .

Die Rückgabe von "404 nicht gefunden" beim Aufrufen von / users / ist beispielsweise verwirrend, da dies Folgendes bedeuten kann:

  • URI ist falsch (HTTP)
  • Es wurden keine Benutzer gefunden (REST)

"403 Verboten / Zugriff verweigert" kann bedeuten:

  • Besondere Erlaubnis erforderlich. Browser können damit umgehen, indem sie den Benutzer / das Passwort fragen. (HTTP)
  • Auf dem Server konfigurierte falsche Zugriffsberechtigungen. (HTTP)
  • Sie müssen authentifiziert sein (REST)

Und die Liste kann mit '500 Server error' (ein Apache / Nginx HTTP-Fehler oder ein Business Constraint-Fehler in REST) ​​oder anderen HTTP-Fehlern usw. fortgesetzt werden.

Aus dem Code ist schwer zu verstehen, was der Fehlergrund, ein HTTP-Fehler (Transportfehler) oder ein REST-Fehler (logisch) war.

Wenn die HTTP-Anforderung physisch erfolgreich ausgeführt wurde, sollte immer 200 Code zurückgegeben werden, unabhängig davon, ob die Datensätze gefunden wurden oder nicht. Weil die URI-Ressource gefunden wurde und vom HTTP-Server verarbeitet wurde. Ja, möglicherweise wird ein leerer Satz zurückgegeben. Ist es möglich, eine leere Webseite mit 200 als HTTP-Ergebnis zu erhalten?

Stattdessen können Sie 200 HTTP-Code mit einigen Optionen zurückgeben:

  • "Fehler" -Objekt in JSON-Ergebnis, wenn etwas schief geht
  • Leeren Sie das JSON-Array / Objekt, wenn kein Datensatz gefunden wurde
  • Ein Bool-Ergebnis- / Erfolgsflag in Kombination mit vorherigen Optionen für eine bessere Handhabung.

Einige Internetanbieter können Ihre Anfragen abfangen und Ihnen einen 404-HTTP-Code zurückgeben. Dies bedeutet nicht, dass Ihre Daten nicht gefunden werden, aber auf Transportebene stimmt etwas nicht.

Aus dem Wiki :

Im Juli 2004 setzte der britische Telekommunikationsanbieter BT Group das Cleanfeed-System zum Blockieren von Inhalten ein, das bei jeder Anforderung von Inhalten, die von der Internet Watch Foundation als potenziell illegal eingestuft wurden, einen 404-Fehler zurückgibt. Andere ISPs geben unter den gleichen Umständen einen "verbotenen" HTTP 403-Fehler zurück. In Thailand und Tunesien wurde auch über die Praxis berichtet, gefälschte 404-Fehler als Mittel zur Verschleierung der Zensur einzusetzen. In Tunesien, wo die Zensur vor der Revolution von 2011 streng war, wurden die Menschen auf die Natur der gefälschten 404-Fehler aufmerksam und schufen einen imaginären Charakter namens "Ammar 404", der "den unsichtbaren Zensor" darstellt.

Warum nicht einfach mit so etwas antworten?

{
  "result": false,
  "error": {"code": 102, "message": "Validation failed: Wrong NAME."}
}

Google gibt in seiner Geokodierungs-API immer 200 als Statuscode zurück, auch wenn die Anforderung logisch fehlschlägt: https://developers.google.com/maps/documentation/geocoding/intro#StatusCodes

Facebook gibt für erfolgreiche HTTP-Anforderungen immer 200 zurück, auch wenn die REST-Anforderung fehlschlägt: https://developers.facebook.com/docs/graph-api/using-graph-api/error-handling

Es ist ganz einfach, HTTP-Statuscodes gelten für HTTP-Anforderungen. Die REST-API ist Ihre, definieren Sie Ihre Statuscodes.

Marcodor
quelle
3
Tatsächlich ist die Verwendung von HTTP-Statuscodes für REST später noch verwirrender: 1) Sie sehen 4xx in der Toolbox Ihres Entwicklers und können nicht durch einen Blick darauf sagen, ob der Server einen vernünftigen Wert zurückgegeben hat oder Ihre Anfrage überhaupt nicht verarbeitet hat und dann 2) sollten alle Ihre Fehler- / Ausnahme- / Fang-Handler überprüfen, welcher Server als Antwort zurückgegeben wurde (meistens nicht, da Sie dies bei jedem Serviceabruf tun müssten), und 3) Sie erhalten dieselbe Nutzlast ( Typ) auf Erfolgs- und Fehlerpfad, der zu kompliziertem / dupliziertem Code führt ... Sehr verwirrend.
Szczepanpp
9
Diese Antwort verwechselt die ursprüngliche Semantik des HTTP-Protokolls mit der Frage, wie REST über HTTP als Architekturstil HTTP zur Implementierung von Webdienst-APIs neu verwendet. Als architektonischer Stil ist REST kein Standard, der strikt befolgt werden muss, sondern ein vorgeschlagener Ansatz. Die Verwendung einer 200-Antwort für einen Validierungsfehler ist nicht richtig oder falsch. Es ist jedoch für Ihre Kunden verwirrend zu antworten, dass die Anforderung erfolgreich war, aber tatsächlich aufgrund eines Validierungsfehlers fehlgeschlagen ist. Dies ist ein wichtiges Detail, das im Hauptteil der Antwort verdeckt ist. Die Semantik, deren Analyse der Client analysieren muss.
Kevin Hooke
5
@Marcodor Wenn Ihr API-Aufruf fehlschlägt, Sie aber 200 zurückgeben, um Erfolg anzuzeigen, wie ist dies eine gute Idee? Es ist unklar und verwirrend für die Verbraucher Ihrer API.
Kevin Hooke
3
Korrigieren Sie aus vielen Gründen, nicht nur die Trennung von HTTP- und REST-Fehlern. Die REST-Validierung erfordert häufig mehr Nuancen. Beispiel: Datensatz akzeptiert, aber als Duplikat markiert oder wegen einer eindeutigen Indexverletzung abgelehnt. Sie möchten auch ein konsistentes Rückgabemodell. Die .NET- BadRequest()Methode verfügt über ein eigenes Rückgabemodell, das sich von Ihrem regulären Rückgabemodell unterscheidet. Das ist ein Albtraum zu analysieren. @ KevinHooke: Wenn Sie HTTP 200 für einen REST-Validierungsfehler zurückgeben, sagen Sie: "Ich habe Ihre Nachricht erhalten, die Antwort lautet" Nein ", und hier ist der Grund dafür." Bei der Rückgabe von HTTP 400 heißt es: "Ich weiß nicht, wovon Sie sprechen."
Neil Laslett
5
Das Argument "Weil Google es tut, muss es richtig sein" ist für mich verrückt. Es ist in Ordnung, etwas herauszufordern, das Google für Kinder implementiert hat. Das Zurückgeben von HTTP 200 für einen erfolglosen Restaufruf verwirrt den Aufrufer der API, es sollte 4xx sein und man kann ein hübsches JSON / XML in den Body aufnehmen ... lassen Sie uns den Wahnsinn gemeinsam stoppen.
Jeryl Cook
43

Ein Duplikat in der Datenbank sollte a sein 409 CONFLICT.

Ich empfehle die Verwendung 422 UNPROCESSABLE ENTITYfür Validierungsfehler.

Ich gebe eine längere Erklärung von 4xx - Codes hier .

Phil Parker
quelle
6

Der Statuscode 304 Nicht geändert würde auch eine akzeptable Antwort auf eine doppelte Anfrage geben. Dies ähnelt der Verarbeitung eines Headers zur If-None-MatchVerwendung eines Entity-Tags.

Meiner Meinung nach ist die Antwort von @ Piskvor die offensichtlichere Wahl für das, was ich als Absicht der ursprünglichen Frage empfinde, aber ich habe eine Alternative, die ebenfalls relevant ist.

Wenn Sie eine doppelte Anforderung als Warnung oder Benachrichtigung und nicht als Fehler behandeln möchten, ist der Antwortstatuscode 304Nicht geändert und der Content-LocationHeader, der die vorhandene Ressource identifiziert, genauso gültig. Wenn lediglich sichergestellt werden soll, dass eine Ressource vorhanden ist, ist eine doppelte Anforderung kein Fehler, sondern eine Bestätigung. Die Anforderung ist nicht falsch, sondern einfach redundant, und der Client kann auf die vorhandene Ressource verweisen.

Mit anderen Worten, die Anforderung ist gut, aber da die Ressource bereits vorhanden ist, muss der Server keine weitere Verarbeitung durchführen.

Suncat2000
quelle
6
Nach meinem Verständnis ist 304 für GET-Operationen vorgesehen, um das Caching zu unterstützen.
Sinaesthetic
6

Der ActiveRecord-Adapter von Ember-Data wird voraussichtlich 422 UNPROCESSABLE ENTITYvom Server zurückgegeben. Wenn Ihr Client in Ember.js geschrieben ist, sollten Sie 422 verwenden. Nur dann werden DS.Errors mit zurückgegebenen Fehlern gefüllt. Sie können 422 natürlich in einen anderen Code in Ihrem Adapter ändern .

Daniel Kmak
quelle