it-swarm.com.de

Welcher HTTP-Statuscode muss zurückgegeben werden, wenn mehrere Aktionen mit unterschiedlichen Status abgeschlossen werden?

Ich erstelle eine API, in der der Benutzer den Server auffordern kann, mehrere Aktionen in einer HTTP-Anforderung auszuführen. Das Ergebnis wird als JSON-Array mit einem Eintrag pro Aktion zurückgegeben.

Jede dieser Aktionen kann unabhängig voneinander fehlschlagen oder erfolgreich sein. Beispielsweise kann die erste Aktion erfolgreich sein, die Eingabe für die zweite Aktion ist möglicherweise schlecht formatiert und kann nicht überprüft werden, und die dritte Aktion kann einen unerwarteten Fehler verursachen.

Wenn es eine Anforderung pro Aktion gäbe, würde ich die Statuscodes 200, 422 bzw. 500 zurückgeben. Aber jetzt, wenn es nur eine Anfrage gibt, welchen Statuscode soll ich zurückgeben?

Einige Optionen:

  • Geben Sie immer 200 zurück und geben Sie detailliertere Informationen im Körper.
  • Befolgen Sie die obige Regel möglicherweise nur, wenn die Anforderung mehr als eine Aktion enthält.
  • Geben Sie möglicherweise 200 zurück, wenn alle Anforderungen erfolgreich sind, andernfalls 500 (oder einen anderen Code)?
  • Verwenden Sie einfach eine Anforderung pro Aktion und akzeptieren Sie den zusätzlichen Aufwand.
  • Etwas ganz anderes?
73
Anders

Die kurze, direkte Antwort

Da die Anforderung von der Ausführung der Liste von Aufgaben spricht (Aufgaben sind die Ressource, von der wir hier sprechen), wird die Aufgabengruppe unabhängig vom Ausführungsergebnis zur Ausführung weitergeleitet ), dann wäre es sinnvoll, dass der Antwortstatus 200 OK lautet. Andernfalls sollte der Antwortstatus dies anzeigen, wenn ein Problem aufgetreten ist, das die Ausführung der Aufgabengruppe verhindern würde, z. B. eine fehlgeschlagene Validierung der Aufgabenobjekte oder wenn ein erforderlicher Dienst nicht verfügbar ist Error. Wenn danach die Ausführung der Aufgaben beginnt und die auszuführenden Aufgaben im Anforderungshauptteil aufgeführt sind, würde ich erwarten, dass die Ausführungsergebnisse im Antworttext aufgeführt werden.


Die lange, philosophische Antwort

Sie erleben dieses Dilemma, weil Sie von dem abweichen, wofür HTTP entwickelt wurde. Sie interagieren nicht mit der Verwaltung von Ressourcen, sondern verwenden sie als Mittel zum Aufrufen von Remotemethoden (was nicht sehr seltsam ist, jedoch ohne ein vorgefasstes Schema schlecht funktioniert).

Mit dem oben Gesagten und ohne den Mut, diese Antwort in einen langjährigen Leitfaden umzuwandeln, ist das Folgende ein URI-Schema, das einem Ressourcenmanagement-Ansatz entspricht:

  • /tasks
    • GET listet alle Aufgaben paginiert auf
    • POST fügt eine einzelne Aufgabe hinzu
  • /tasks/task/[id]
    • GET antwortet mit dem Statusobjekt einer einzelnen Aufgabe
    • DELETE bricht eine Aufgabe ab/löscht sie
  • /tasks/groups
    • GET listet alle paginierten Aufgabengruppen auf
    • POST fügt eine Gruppe von Aufgaben hinzu
  • /tasks/groups/group/[id]
    • GET antwortet mit dem Status einer Taskgruppe
    • DELETE bricht die Aufgabengruppe ab/löscht sie

In dieser Struktur geht es um Ressourcen, nicht darum, was mit ihnen zu tun ist. Was mit Ressourcen gemacht wird, ist das Anliegen eines anderen Dienstes.

Ein weiterer wichtiger Punkt ist, dass es ratsam ist, in einem HTTP-Anforderungshandler nicht sehr lange zu blockieren. Ähnlich wie die Benutzeroberfläche sollte eine HTTP-Schnittstelle reagieren - in einer Zeitskala, die einige Größenordnungen langsamer ist (da diese Schicht sich mit E/A befasst).

Der Schritt zum Entwerfen einer HTTP-Schnittstelle, die Ressourcen streng verwaltet, ist wahrscheinlich genauso schwierig wie das Entfernen der Arbeit von einem UI-Thread, wenn auf eine Schaltfläche geklickt wird. Es ist erforderlich, dass der HTTP-Server mit anderen Diensten kommuniziert, um Aufgaben auszuführen, anstatt sie im Anforderungshandler auszuführen. Dies ist keine flache Implementierung, sondern eine Richtungsänderung.


Einige Beispiele für die Verwendung eines solchen URI-Schemas

Eine einzelne Aufgabe ausführen und den Fortschritt verfolgen :

  • POST /tasks Mit der auszuführenden Aufgabe
    • GET /tasks/task/[id] Bis das Antwortobjekt completed einen positiven Wert hat und gleichzeitig den aktuellen Status/Fortschritt anzeigt

Eine einzelne Aufgabe ausführen und auf ihren Abschluss warten :

  • POST /tasks Mit der auszuführenden Aufgabe
    • GET /tasks/task/[id]?awaitCompletion=true Bis completed einen positiven Wert hat (wahrscheinlich eine Zeitüberschreitung, weshalb dies wiederholt werden sollte)

Ausführen einer Aufgabengruppe und Verfolgen des Fortschritts :

  • POST /tasks/groups Mit der Gruppe der auszuführenden Aufgaben
    • GET /tasks/groups/group/[groupId] Bis die Eigenschaft des Antwortobjekts completed einen Wert hat, der den Status der einzelnen Aufgaben anzeigt (z. B. 3 von 5 Aufgaben erledigt)

Anforderung einer Ausführung für eine Aufgabengruppe und Warten auf deren Abschluss :

  • POST /tasks/groups Mit der Gruppe der auszuführenden Aufgaben
    • GET /tasks/groups/group/[groupId]?awaitCompletion=true Bis antwortet mit einem Ergebnis, das den Abschluss anzeigt (hat wahrscheinlich eine Zeitüberschreitung, weshalb eine Schleife durchgeführt werden sollte)
22
Ben Barkay

Meine Stimme wäre, diese Aufgaben in separate Anfragen aufzuteilen. Wenn jedoch zu viele Hin- und Rückflüge ein Problem darstellen, bin ich auf HTTP-Antwortcode 207 - Multi-Status gestoßen.

Kopieren/Einfügen von diesem Link:

Eine Antwort mit mehreren Status übermittelt Informationen zu mehreren Ressourcen in Situationen, in denen möglicherweise mehrere Statuscodes geeignet sind. Der Standard-Multi-Status-Antworttext ist eine HTTP-Entität text/xml oder application/xml mit einem Stammelement 'multistatus'. Weitere Elemente enthalten Statuscodes der Serien 200, 300, 400 und 500, die während des Methodenaufrufs generiert wurden. 100 Serienstatuscodes sollten NICHT in einem 'Antwort'-XML-Element aufgezeichnet werden.

Obwohl '207' als Gesamtantwortstatuscode verwendet wird, muss der Empfänger den Inhalt des Multistatus-Antwortkörpers konsultieren, um weitere Informationen über den Erfolg oder Misserfolg der Methodenausführung zu erhalten. Die Antwort kann in Erfolgs-, Teilerfolgs- und auch in Fehlersituationen verwendet werden.

87
neilsimp1

Obwohl Multi-Status eine Option ist, würde ich 200 (Alles ist in Ordnung) zurückgeben, wenn alle Anfragen erfolgreich waren, und ansonsten einen Fehler (500 oder vielleicht 207).

Der Standardfall sollte normalerweise 200 sein - alles funktioniert. Und Kunden sollten nur danach suchen müssen. Und nur wenn der Fehlerfall aufgetreten ist, können Sie eine 500 (oder eine 207) zurückgeben. Ich denke, der 207 ist eine gültige Wahl für den Fall von mindestens einem Fehler, aber wenn Sie das gesamte Paket als eine Transaktion sehen, können Sie auch 500 senden. - Der Client wird die Fehlermeldung so oder so interpretieren wollen.

Warum nicht immer 207 senden? - Weil Standardfälle einfach und Standard sein sollten. Während Ausnahmefälle außergewöhnlich sein können. Ein Kunde sollte den Antworttext nur lesen und weitere komplexe Entscheidungen treffen müssen, wenn eine Ausnahmesituation dies rechtfertigt.

23
Falco

Eine Möglichkeit wäre, immer einen Statuscode 200 zurückzugeben und dann bestimmte Fehler in Ihrem JSON-Dokumententext zurückzugeben. Genau so sind einige APIs aufgebaut (sie geben immer einen Statuscode 200 zurück und lösen den Fehler im Body aus). Weitere Informationen zu den verschiedenen Ansätzen finden Sie unter http://archive.oreilly.com/pub/post/restful_error_handling.html

13
BigONotation

Ich denke, neilsimp1 ist korrekt, aber ich würde empfehlen, die gesendeten Daten so umzugestalten, dass Sie einen 206 - Accepted Senden und die Daten später verarbeiten können. Vielleicht mit Rückrufen.

Das Problem beim Versuch, mehrere Aktionen in einer einzigen Anforderung zu senden, ist genau die Tatsache, dass jede Aktion ihren eigenen "Status" haben sollte.

Betrachtet man den Import einer CSV (ich weiß nicht wirklich, worum es beim OP geht, aber es ist eine einfache Version). POST die CSV und erhalte eine 206. Dann kann die CSV später importiert werden und Sie können den Status des Imports mit einem GET (200) gegen eine URL abrufen, die Fehler pro Zeile anzeigt.

POST /imports/ -> 206
GET  /imports/1 -> 200
GET  /imports/1/errors -> 200 -> Has a list of errors

Das gleiche Muster kann auf viele Batch-Operationen angewendet werden

POST /operations/ -> 206
GET  /operations/1 -> 200
GET  /operations/1/errors -> 200 - > Has a list of errors.

Der Code, der die POST] verarbeitet, muss nur überprüfen, ob das Format der Operationsdaten gültig ist. Zu einem späteren Zeitpunkt können die Operationen dann ausgeführt werden. In einem Hintergrundarbeiter können Sie die Skalierung vereinfachen Sie können dann jederzeit den Status der Vorgänge überprüfen. Sie können Abfragen oder Rückrufe oder Streams oder was auch immer verwenden, um die Notwendigkeit zu beheben, zu wissen, wann eine Reihe von Vorgängen abgeschlossen ist.

4
coteyr

Hier gibt es bereits viele gute Antworten, aber ein Aspekt fehlt:

Was ist der Vertrag, den Ihre Kunden erwarten?

HTTP-Rückkehrcodes sollten mindestens eine Unterscheidung zwischen Erfolg und Misserfolg anzeigen und daher die Rolle der "Ausnahmen des armen Mannes" spielen. Dann bedeutet 200 "Vertrag vollständig erfüllt" und 4xx oder 5xx bedeuten Nichterfüllung.

Naiv würde ich erwarten, dass der Vertrag Ihrer Anfrage für mehrere Aktionen "alle meine Aufgaben erledigen" lautet. Wenn eine davon fehlschlägt, war die Anfrage nicht (vollständig) erfolgreich. Normalerweise würde ich als Kunde 200 als "alles in Ordnung" verstehen, und Codes aus der 400- und 500-Familie zwingen mich, über die Folgen eines (teilweisen) Fehlers nachzudenken. Verwenden Sie also 200 für "alle erledigten Aufgaben" und 500 plus eine beschreibende Antwort für den Fall eines teilweisen Fehlers.

Ein anderer hypothetischer Vertrag könnte darin bestehen, "alle Aktionen auszuführen". Dann ist es völlig vertragsgemäß, wenn (einige) der Aktionen fehlschlagen. Sie würden also immer 200 plus ein Ergebnisdokument zurückgeben, in dem Sie die Erfolgs-/Fehlerinformationen für die einzelnen Aufgaben finden.

Also, was ist der Vertrag, dem Sie folgen möchten? Beide sind gültig, aber die erste (200 nur für den Fall, dass alles erledigt wurde) ist für mich intuitiver und entspricht besser den typischen Softwaremustern. In den (hoffentlich) meisten Fällen, in denen der Service alle Aufgaben erledigt hat, kann der Kunde diesen Fall problemlos erkennen.

Ein letzter wichtiger Aspekt: ​​Wie teilen Sie Ihren Kunden Ihre Vertragsentscheidung mit? Z.B. In Java würde ich Methodennamen wie "doAll ()" oder "tryToDoAll ()" verwenden. In HTTP können Sie die Endpunkt-URLs entsprechend benennen, in der Hoffnung, dass Ihre Client-Entwickler die Benennung sehen, lesen und verstehen (darauf würde ich nicht wetten). Ein Grund mehr, den Vertrag mit der geringsten Überraschung zu wählen.

2
Ralf Kleberhoff

Antworten:

Verwenden Sie einfach eine Anforderung pro Aktion und akzeptieren Sie den zusätzlichen Aufwand.

Ein Statuscode beschreibt den Status einer Operation. Daher ist es sinnvoll, eine Operation pro Anforderung durchzuführen.

Mehrere unabhängige Operationen brechen das Prinzip, auf dem das Anforderungs-Antwort-Modell und die Statuscodes basieren. Du kämpfst gegen die Natur.

HTTP/1.1 und HTTP/2 haben den Overhead von HTTP-Anforderungen erheblich verringert. Ich schätze, dass es nur sehr wenige Situationen gibt, in denen es ratsam ist, unabhängige Anfragen zu stapeln.


Das gesagt,

(1) Mit einer PATCH-Anforderung können Sie mehrere Änderungen vornehmen ( RFC 5789 ). Dies setzt jedoch voraus, dass die Änderungen nicht unabhängig sind; Sie werden atomar angewendet (alles oder nichts).

(2) Andere haben auf den 207 Multi-Status-Code hingewiesen. Dies ist jedoch nur für WebDAV ( RFC 4918 ) definiert, eine Erweiterung von HTTP.

Der Statuscode 207 (Multi-Status) bietet den Status für mehrere unabhängige Vorgänge (weitere Informationen finden Sie in Abschnitt 13).

...

Eine Antwort mit mehreren Status übermittelt Informationen zu mehreren Ressourcen in Situationen, in denen möglicherweise mehrere Statuscodes geeignet sind. Das 'XML-Element' 'multistatus' 'enthält null oder mehr' Antwort'-Elemente in beliebiger Reihenfolge mit Informationen zu einer einzelnen Ressource.

Eine WebDAV-XML-Antwort von 207 wäre so seltsam wie eine Ente in einer Nicht-WebDAV-API. Tu das nicht.

0
Paul Draper

Wenn Sie wirklich mehrere Aktionen in einer Anfrage benötigen, können Sie alle Aktionen in eine Transaktion im Backend einbinden. Auf diese Weise sind sie entweder alle erfolgreich oder alle scheitern.

Als Client, der die API verwendet, kann ich bei einem API-Aufruf mit vollständigem Erfolg oder Misserfolg umgehen. Teilerfolg ist schwer zu bewältigen, da ich mit allen möglichen resultierenden Zuständen umgehen müsste.

0
Dean