Webentwicklung

HTTP 202 Accepted für lang laufende APIs - Eine Operation statt eines Erfolgsversprechens

HTTP 202 Accepted für lang laufende APIs - Eine Operation statt eines Erfolgsversprechens

Ein Client fordert eine API auf, einen umfangreichen Bericht zu erzeugen. Die Arbeit kann mehrere Minuten dauern, sodass es fragil wäre, eine einzelne HTTP-Verbindung so lange offenzuhalten. Eine sofortige Antwort erscheint sinnvoll, doch was kann diese Antwort wahrheitsgemäß aussagen? Bei 200 OK wirkt der Bericht bereits fertig. Bei 202 Accepted hat sich das schwierige Problem nur verlagert: Der Client muss weiterhin erfahren, ob die Arbeit erfolgreich war, fehlgeschlagen ist oder nie begonnen hat.

202 ist gerade deshalb nützlich, weil der Status nur ein eng begrenztes Versprechen abgibt. Er ist keine Abkürzung für „der Server wird sich vermutlich darum kümmern“. Eine verlässliche asynchrone API benötigt rund um diesen Statuscode eine beobachtbare Operationsressource mit eindeutigen Zuständen, Fehlerinformationen, Zugriffskontrolle und einem für den Client verständlichen Lebenszyklus.

Was 202 tatsächlich aussagt

RFC 9110 definiert 202 Accepted als eine zur Verarbeitung angenommene Anfrage, deren Verarbeitung noch nicht abgeschlossen ist. Die Arbeit kann später abgelehnt oder möglicherweise überhaupt nicht ausgeführt werden. Die Antwort ist bewusst unverbindlich.

Dieses letzte Wort ist entscheidend. Die erfolgreiche Klasse 2xx macht 202 nicht zum Beleg dafür, dass das angeforderte fachliche Ergebnis erreicht wurde. Der Status besagt, dass der Server die Anfrage in einen späteren Prozess aufgenommen hat. Der RFC weist außerdem darauf hin, dass HTTP keine Möglichkeit bietet, nachträglich einen Statuscode aus dieser asynchronen Operation zu senden. Der Server kann das ursprüngliche 202 nicht rückwirkend durch 201 Created oder 500 Internal Server Error ersetzen.

Dieselbe Spezifikation besagt, dass die Darstellung der Antwort den aktuellen Status der Anfrage beschreiben und auf einen Statusmonitor verweisen oder ihn einbetten sollte. Das ist eine Empfehlung und kein universelles Übertragungsformat. HTTP definiert die Bedeutung von 202; die API muss weiterhin festlegen, wie Clients alles Folgende beobachten.

Anfrage, Operation und Ergebnis trennen

Drei Identitäten lassen sich leicht vermischen:

  1. Die eingereichte Anfrage fordert den Server auf, die Arbeit zu beginnen.
  2. Die Operationsressource repräsentiert genau diese Ausführung und ihren wechselnden Zustand.
  3. Die Ergebnisressource ist der Bericht, Export, Account oder ein anderes Domänenobjekt, das bei erfolgreicher Operation entsteht.

Die Operation ist nicht nur ein Implementierungsdetail. Sie ist der dauerhafte Bezugspunkt des Clients für die bestehende Unsicherheit. Ein illustrativer Austausch könnte so aussehen:

POST /reports HTTP/1.1
Host: api.example.test
Content-Type: application/json

{"from":"2026-10-01","to":"2026-10-31"}

HTTP/1.1 202 Accepted
Location: /operations/op_7f31
Content-Type: application/json

{
  "id": "op_7f31",
  "status": "pending",
  "status_url": "/operations/op_7f31"
}

Die Feldnamen sind Entscheidungen der Anwendung, und Location ist ein verbreitetes Muster, keine Vorschrift für jede 202-Antwort. Entscheidend ist, dass der Vertrag einen stabilen Ort benennt, an dem ein berechtigter Client den Ausgang abfragen kann.

Die Operation als kleine Zustandsmaschine modellieren

Eine lose Textmeldung wie „wird noch verarbeitet“ lässt sich nur schwer automatisieren. Eine begrenzte Menge dokumentierter Zustände ist eindeutiger. Eine kleine API könnte pending, running, succeeded, failed und canceled verwenden. Andere Bezeichnungen sind möglich, doch Clients müssen wissen, welche Zustände terminal sind und welche sich noch ändern können.

{
  "id": "op_7f31",
  "status": "running",
  "created_at": "2026-11-07T00:12:00Z",
  "updated_at": "2026-11-07T00:12:08Z",
  "progress": null,
  "result_url": null,
  "error": null
}

progress sollte optional sein. Manche Jobs besitzen messbare Einheiten; andere verbringen den Großteil ihrer Zeit in einem einzigen unvorhersehbaren Schritt. Ein erfundener Prozentwert ist schlechter als gar keiner, weil er Unsicherheit in irreführende Genauigkeit verwandelt. Zeitstempel, der aktuelle Zustand und eine kurze Beschreibung können ausreichen.

Googles Leitlinie für lang laufende Operationen verwendet dieselbe grundsätzliche Trennung: Eine aktive Operation enthält Metadaten und schließlich entweder eine Antwort oder einen Fehler. Das genaue Schema ist Google-spezifisch und kein allgemeiner HTTP-Standard, doch die Unterscheidung ist übertragbar. Ein Abschluss benötigt ein maschinenlesbares Ergebnis und nicht nur das Verschwinden von „pending“.

Zuerst validieren, dann dauerhaft annehmen

Asynchrone Verarbeitung rechtfertigt keine verzögerte Validierung. Authentifizierung, Autorisierung, Medientyp, grundlegende Syntax, Pflichtfelder und kostengünstig prüfbare fachliche Vorbedingungen sollten vor der Rückgabe von 202 kontrolliert werden. Weiß der Server bereits, dass die Anfrage ungültig oder unzulässig ist, sollte er sofort den passenden Fehler zurückgeben, statt eine Operation zu erzeugen, die sicher scheitern wird.

Die Annahme benötigt außerdem eine sinnvolle Dauerhaftigkeitsgrenze. Gibt die API 202 zurück und verliert anschließend bei einem Prozessneustart eine nur im Arbeitsspeicher gehaltene Aufgabe, vermittelt der Statuscode mehr Verlässlichkeit, als die Implementierung verdient. Eine kleine Anwendung könnte vor der Antwort einen Operationsdatensatz und einen Queue-Eintrag in einer Datenbank committen. Ein anderes System könnte sich auf einen dauerhaften Message Broker stützen. Die konkrete Technik ist zweitrangig; die Antwort sollte erst nach dem Punkt folgen, an dem die Anwendung genügend Informationen gespeichert hat, um fortzufahren oder einen Fehler sichtbar zu machen.

Das garantiert nicht das endgültige Ergebnis. Ein Worker kann weiterhin ausfallen, eine Abhängigkeit kann die Operation ablehnen oder ein Administrator kann sie abbrechen. Die dauerhafte Annahme macht nur das anfängliche Versprechen wahrheitsgemäß: Die Anwendung kann über die angenommene Operation Rechenschaft ablegen, statt sie still zu vergessen.

Polling ist ein Vertrag, keine enge Schleife

Ein Client kann die Operationsressource per GET abrufen, bis sie einen terminalen Zustand erreicht. Die API sollte eine angemessene Polling-Strategie dokumentieren. Ohne Vorgabe fragen viele Clients so schnell ab, wie ihre Schleifen laufen, und erzeugen Last, die die Arbeit nicht schneller beendet.

Das asynchrone Request-Reply-Muster von Microsoft empfiehlt die Rückgabe einer Statusadresse und verwendet Retry-After als Polling-Hinweis. Das ist hilfreiche Entwurfsorientierung, doch Retry-After ist kein speziell vorgeschriebener Bestandteil jeder 202-Antwort. Ob der Wert eine Verzögerung angibt, ob Clients Backoff anwenden und ob sich die Schätzung verändert, sollte Teil des dokumentierten API-Vertrags sein.

Statusantworten benötigen außerdem eine ausdrückliche Cache-Richtlinie. Ein gemeinsam genutzter Cache oder Browser-Cache, der eine alte pending-Darstellung ausliefert, kann eine abgeschlossene Operation blockiert erscheinen lassen. Eine API kann ungeeignete Speicherung verhindern oder Validatoren und Revalidierung bewusst definieren. Die passende Richtlinie hängt davon ab, ob Operationsdaten privat sind, wie häufig sie sich ändern und ob Caching einen tatsächlichen Nutzen bietet.

Den Abschluss darstellen, ohne die Historie umzuschreiben

Wenn der Bericht bereitsteht, kann die Operationsressource eine normale 200 OK-Darstellung mit status: succeeded und einem Link zum Ergebnis bleiben:

HTTP/1.1 200 OK
Content-Type: application/json

{
  "id": "op_7f31",
  "status": "succeeded",
  "result_url": "/reports/report_91c2",
  "error": null
}

Ein anderer dokumentierter Entwurf kann am Statusendpunkt 303 See Other zurückgeben und die Ergebnis-URI in Location setzen. Microsoft beschreibt diese Variante, weil 303 den Client anweist, eine andere Ressource per GET abzurufen. Sie ist eine Option und nicht das vorgeschriebene Ende aller asynchronen APIs. Eine abschließende Operationsdarstellung beizubehalten ist häufig nützlich, wenn Clients Abschlussmetadaten oder einen Audit-Trail benötigen.

Für Fehler gilt dasselbe Prinzip. Das ursprüngliche 202 bleibt historisch korrekt: Die Anfrage wurde angenommen. Eine spätere Operationsdarstellung hält fest, dass die Ausführung fehlgeschlagen ist, und liefert ein stabiles, begrenztes Fehlerobjekt. Die API sollte einen terminalen fachlichen oder verarbeitungsbezogenen Fehler von einer vorübergehenden Störung beim Lesen des Statusendpunkts unterscheiden. Das sind verschiedene Ereignisse, die unterschiedliches Clientverhalten erfordern können.

Fehler, Autorisierung und Ablauf gemeinsam entwerfen

Eine Operations-URL kann Kundennamen, Exportparameter, Fehlerdetails oder Links zu erzeugten Dateien offenlegen. Ein schwer zu erratender Bezeichner ist nützlich, aber keine Autorisierung. Jede Status-, Ergebnis- und Abbruchanfrage muss gegen den aufrufenden Benutzer und den Mandanten geprüft werden, denen die Operation gehört. Logs sollten sensible Anfragedaten nicht allein deshalb kopieren, weil der Job im Hintergrund läuft.

Operationsdatensätze dürfen auch nicht unbeabsichtigt ewig bestehen bleiben. Der Vertrag sollte angeben, wie lange abgeschlossene Operationen und erzeugte Ergebnisse verfügbar bleiben und was Clients nach dem Ablauf erhalten. AIP-151 erlaubt ausdrücklich, Operationsressourcen ablaufen zu lassen, während auch das Microsoft-Muster eine Aufbewahrungsrichtlinie empfiehlt. Keine der beiden Quellen legt eine universelle Dauer für eine kleine API fest. Speicherkosten, Audit-Anforderungen, Datenschutz und realistische Wiederherstellungszeiträume für Clients bestimmen diese Entscheidung.

Auch ein Abbruch verlangt Zurückhaltung. Eine API kann DELETE /operations/op_7f31 oder eine andere Abbruchaktion anbieten, doch eine Abbruchanfrage beweist nicht, dass jede Nebenwirkung rückgängig gemacht wurde. Der Worker kann bereits eine unumkehrbare Grenze überschritten haben. Der Vertrag sollte erklären, ob der Abbruch nach bestem Bemühen erfolgt, welche Zustände ihn akzeptieren und ob teilweise ausgeführte Arbeit eine Kompensation erfordert.

Prefer kann einen Clientwunsch ausdrücken, keinen Befehl

RFC 7240 definiert Prefer: respond-async, damit ein Client seine Präferenz für asynchrone Verarbeitung ausdrücken kann. Er definiert außerdem die optionale Präferenz wait. Ein Server darf Präferenzen ignorieren, und der RFC lässt den Mechanismus zum Abrufen des endgültigen Ergebnisses bewusst implementationsspezifisch.

Dieser Header ist wertvoll, wenn ein Endpunkt zwischen einer schnellen synchronen Antwort und einer Operationsressource wählen kann. Er ist nicht erforderlich, wenn der API-Vertrag die Operation stets asynchron verarbeitet, und er repariert keine API ohne Status- und Fehlersemantik. Präferenzaushandlung und Operationsentwurf lösen unterschiedliche Probleme.

Wann 202 das falsche Werkzeug ist

Eine Operationsressource verursacht zusätzliche Schreibvorgänge, Polling-Datenverkehr, Bereinigung, Autorisierungsregeln, Clientzustände und Monitoring. Kann der Server die Anfrage zeitnah und zuverlässig abschließen, ist eine gewöhnliche endgültige Antwort einfacher und informativer. Dass JavaScript nicht blockierend arbeitet, rechtfertigt für sich genommen kein serverseitiges 202; ein Client kann auf eine normale HTTP-Antwort warten, ohne seine Benutzeroberfläche einzufrieren.

Polling eignet sich ebenfalls nicht für jede Arbeitslast. Server-Sent Events, WebSockets, Webhooks oder eine nachrichtenorientierte Schnittstelle können besser zu Clients passen, die Aktualisierungen mit geringer Latenz benötigen oder viele Ergebnisse verarbeiten. Diese Alternativen haben eigene Kosten für Verbindungen, Zustellung und Sicherheit. Die Entscheidung lautet nicht „modern gegen alt“, sondern welches Beobachtungsmodell beide Seiten ehrlich unterstützen können.

Eine kompakte Prüfliste

  • Bekannte Authentifizierungs-, Autorisierungs-, Syntax- und Validierungsfehler vor der Rückgabe von 202 ablehnen.
  • Genügend Operationszustand dauerhaft speichern, damit er den Anfrageprozess überlebt, bevor die Annahme bestätigt wird.
  • Jeder Operation eine stabile, autorisierte Statusressource geben.
  • Nichtterminale und terminale Zustände einschließlich Fehler und Abbruch dokumentieren.
  • Keine Fortschrittswerte erfinden, wenn der Fortschritt nicht messbar ist.
  • Polling-Hinweise, Cache-Verhalten und Rate Limits definieren.
  • Das spätere Ergebnis oder den Fehler maschinenlesbar gestalten.
  • Aufbewahrung, Ablauf und das Verhalten nach dem Entfernen von Datensätzen definieren.
  • Worker-Abstürze, doppelte Einreichungen, verlorene erste Antworten, Statusautorisierung, terminale Fehler und Abbruchrennen testen.
  • 202 nur verwenden, wenn die Trennung von Annahme und Abschluss den zusätzlichen Protokollzustand rechtfertigt.

Fazit

202 Accepted ist kein Erfolgsversprechen. Der Status ist eine ehrliche Aussage, dass die Verantwortung über den aktuellen HTTP-Austausch hinaus verschoben wurde. Diese Ehrlichkeit bleibt nur bestehen, wenn die API dem Client eine dauerhafte Operationsidentität und einen klaren Weg zu Erfolg, Fehler, Abbruch oder Ablauf bietet.

Für eine kleine API kann der Entwurf bescheiden bleiben: zuerst validieren, die Operation dauerhaft erfassen, einen Statuslink zurückgeben, eine begrenzte Zustandsmaschine bereitstellen und das terminale Ergebnis für einen dokumentierten Zeitraum aufbewahren. Die offene Frage sollte nicht lauten: „Ist der Background Worker wahrscheinlich gelaufen?“ Sie sollte durch die Operationsressource tatsächlich beantwortbar sein.

References