Start / Seminare / Moderne API-Entwicklung mit REST, OpenAPI und Contract Testing
Modul
Requests, Responses und Fehler robust gestalten
4 Kapitel in diesem Modul-Video · Laufzeit
Transkript
Der gesprochene Text dieses Moduls zum Mitlesen, Überfliegen und Durchsuchen. Ein Klick auf einen Zeitstempel springt an die Stelle im Video.
Requests, Responses und Fehler robust gestalten
0:00 Es gibt einen Teil Ihrer API, den Ihre Consumer besonders gründlich lesen — und es ist nicht der Erfolgsfall. Es ist der Fehler. Wenn etwas nicht funktioniert, sitzt jemand vor Ihrer Antwort und versucht herauszufinden, ob er einen Fehler gemacht hat, ob er es noch einmal versuchen darf oder ob er einfach warten muss. In diesem Modul geht es darum, diese Antwort so zu gestalten, dass sie diese Fragen beantwortet — und darum, wie eine Bestellung eine abgebrochene Verbindung übersteht, ohne doppelt im System zu landen.
Requests, Responses und Fehler robust gestalten
0:29 Wir schließen den ersten Tag mit drei Themen ab, die eng zusammenhängen. Zuerst die Frage, wie Repräsentationen konsistent bleiben — über Endpunkte und über Teamgrenzen hinweg. Dann das Standardformat für Fehler nach RFC 9457, das viele Diskussionen ein für alle Mal erledigt. Und zum Schluss die unangenehmste Situation im verteilten System: Der Client bekommt keine Antwort und weiß nicht, ob seine Anfrage angekommen ist.
Repräsentationen konsistent gestalten
0:56 Fangen wir mit etwas an, das unspektakulär klingt und im Alltag enorm viel Reibung erzeugt: Konsistenz. Nicht Schönheit, nicht Eleganz — schlicht die Zusage, dass gleiche Dinge überall gleich aussehen. Denn eine API, deren Felder überall gleich heißen und gleich aufgebaut sind, kann ein Consumer nach dem dritten Endpunkt erraten.
1:17 Eine inkonsistente kostet ihn bei jedem neuen Aufruf Zeit. Denken Sie an ein Formular, das eine Behörde Ihnen schickt. Wenn auf Seite eins nach dem Geburtsdatum gefragt wird und auf Seite drei nach dem Geburtstag, im Format anders, dann ist das kein Fehler — aber es kostet jeden Ausfüllenden Zeit und produziert Fehler. Genau das passiert in APIs, die über Jahre von mehreren Teams gewachsen sind. Konsistenz heißt: Gleiche Sachverhalte heißen überall gleich und sind gleich aufgebaut.
1:46 Das ist keine ästhetische Frage. Es ist die Grundlage dafür, dass ein Consumer Ihre API nach dem dritten Endpunkt erraten kann. Diese vier Entscheidungen kosten in Summe eine halbe Stunde, wenn man sie am Anfang trifft. Später kosten sie ein Major Release. Besonders unterschätzt ist die zweite: der Umgang mit unbekannten Werten.
2:06 Ob ein Feld fehlt, auf null steht oder als leerer String kommt, macht für jeden Consumer einen Unterschied — und wenn Ihre API alle drei Varianten kennt, muss er alle drei behandeln. Die vierte Festlegung ist die, die am häufigsten schmerzt: Geldbeträge als Gleitkommazahl. Das rächt sich spätestens bei der ersten Rundungsdifferenz in der Buchhaltung.
2:27 Achten Sie hier auf zwei Details, die bewusst gesetzt sind. Erstens der Betrag: Er steht als Zeichenkette und trägt seine Währung bei sich. Damit entscheidet nicht mehr die Zahlenbibliothek des Consumers über die Rundung, und niemand muss raten, ob es Euro oder Franken sind. Zweitens der Zeitstempel: Er trägt seine Zone. Ein Lieferfenster ohne Zone ist eine Einladung für Fehler, die genau zweimal im Jahr auftreten — bei der Zeitumstellung.
2:54 Solche Entscheidungen sieht man einer API nicht an. Man merkt sie nur, wenn sie fehlen. Der zweite Punkt ist der klassische Organisationsfehler: Zwei Teams, zwei Sprachen, eine API. Das passiert nicht aus Nachlässigkeit, sondern weil niemand eine gemeinsame Festlegung getroffen hat. Genau dafür gibt es Style Guides, die wir in Modul 7 behandeln.
3:15 Der letzte Punkt ist tückischer, als er klingt: Übersetzte Aufzählungswerte. Sie sehen in der Antwort hübsch aus, aber ein Consumer kann sie nicht mehr vergleichen — und wenn Sie die Übersetzung ändern, brechen Sie ihn, ohne den Vertrag angefasst zu haben.
Fehler nach RFC 9457 beschreiben
3:31 Jetzt zum wichtigsten Teil dieses Moduls. Es gibt ein standardisiertes Format für Fehlerantworten, es ist erfreulich schlicht, und es erspart Ihnen die Diskussion, die sonst in jedem Projekt neu geführt wird. Fehlerformate sind das Thema, das in jedem Projekt neu erfunden wird — obwohl es seit Jahren einen Standard gibt, der die Sache erledigt.
3:51 Wer das Format unter dem Namen RFC 7807 kennt: Das ist die alte Nummer, RFC 9457 hat sie abgelöst. Inhaltlich hat sich wenig geändert, hinzugekommen sind unter anderem eine Registry für verbreitete Problemtypen und Klarstellungen für den Fall, dass die Typ-Adresse nicht abrufbar ist. Das Prinzip ist bestechend einfach: ein eigener Medientyp, application/problem+json, und fünf Elemente, die immer dieselbe Bedeutung haben.
4:18 Damit weiß jeder Consumer sofort, wie er einen Fehler auswerten muss — auch bei einer API, die er noch nie gesehen hat. Die entscheidende Spalte ist die rechte. Zwei Elemente sind stabil und zwei ändern sich bei jedem Vorfall — und diese Unterscheidung bestimmt, wie ein Consumer damit umgehen darf. Der type ist der Schlüssel: An ihm und nur an ihm unterscheidet man Fehlerarten. Der title darf übersetzt werden und ist deshalb als Fallunterscheidung untauglich.
4:47 Interessant ist auch das status-Feld: Es ist laut RFC ausdrücklich nur eine Bequemlichkeit für den Leser. Verbindlich ist der Statuscode der Antwort selbst — beide müssen natürlich übereinstimmen. Schauen Sie auf das letzte Feld. Es gehört nicht zu den fünf Standardelementen, sondern ist eine Erweiterung — und genau darin liegt die Stärke des Formats.
5:08 Sie dürfen fachliche Zusatzinformationen mitgeben, und der Standard verlangt ausdrücklich, dass Consumer unbekannte Erweiterungen ignorieren. Das heißt: Sie können später Felder hinzufügen, ohne jemanden zu brechen. Und dieses eine Feld macht aus einer Absage einen Vorschlag — die App kann dem Kunden direkt das nächste freie Lieferfenster anbieten, statt ihn suchen zu lassen.
5:30 Ein Standard ist dann gut, wenn er auch sagt, wann man ihn nicht braucht. Ein schlichtes 403 ohne weitere Bedeutung braucht keinen Rumpf — der Statuscode sagt bereits alles. Und wenn Ihre Branche ein eigenes, etabliertes Fehlerformat hat, ist das die bessere Wahl, weil die Werkzeuge es verstehen. Der dritte Punkt ist der wichtigste im Alltag: Problem Details sind nicht für die Fehlersuche gedacht.
5:53 Was Ihre Entwickler zum Debuggen brauchen, gehört ins Log, nicht in die Antwort. Der zweite Punkt begegnet mir häufig: Der type zeigt auf eine schöne Adresse unter der eigenen Domain, und dort steht nichts. Das ist kein Beinbruch — der RFC erlaubt ausdrücklich, dass die Adresse nicht abrufbar ist. Aber wenn Sie sie schon vergeben, dann dokumentieren Sie sie auch; sie ist der natürliche Ort für die Erklärung.
6:17 Der dritte Punkt ist ein echtes Sicherheitsthema: Ein Stacktrace im detail-Feld verrät Frameworkversionen, Pfade und manchmal Datenbankstrukturen. Das gehört nie nach außen.
Wiederholbarkeit und Nachvollziehbarkeit
6:28 Zum Abschluss des ersten Tages die Situation, die im verteilten System am meisten Nerven kostet: Die Anfrage ist raus, die Antwort kommt nicht. Und jetzt? Sie ist der Grund, warum Bestellungen doppelt im System landen. Und die Lösung dafür ist erfreulich unspektakulär, wenn man sie einmal kennt. Diese Situation ist grundsätzlich nicht auflösbar. Wenn keine Antwort kommt, kann der Client nicht wissen, ob die Anfrage nie ankam oder ob nur die Antwort verloren ging.
6:56 Beides sieht identisch aus. Bei einem GET ist das egal, bei einem PUT auch — die sind idempotent. Bei einer Bestellung nicht: Wiederholen kann eine zweite Bestellung erzeugen, nicht wiederholen kann eine verlorene bedeuten. Die Lösung besteht darin, die Entscheidung auf die Serverseite zu verlagern. Der Client schickt einen Schlüssel mit, und der Server erkennt daran die Wiederholung.
7:20 Der rote Faden ist: Der Client vergibt den Schlüssel, nicht der Server. Das ist der Kern, und der erste Schritt sagt auch, wofür — je fachlichem Vorgang einer, nicht je HTTP-Anfrage. Der Server merkt sich dann Schlüssel, Ergebnis und Statuscode und liefert bei einer Wiederholung exakt dieselbe Antwort noch einmal. Für den Client sieht es aus, als wäre die erste Antwort doch noch angekommen.
7:43 Ein Hinweis zur Einordnung: Der Header stammt aus einem IETF-Entwurf, ist also kein verabschiedeter Standard — aber er ist der Weg, den die Branche geht. Wenn ein Kunde anruft, weil seine Bestellung nicht angekommen ist, entscheidet sich hier, ob Sie in fünf Minuten oder in zwei Stunden antworten können. Eine Correlation-ID, die der Consumer setzt und die durch alle beteiligten Dienste wandert, macht aus einer Suche im Heuhaufen eine einzige Abfrage.
8:09 Und beachten Sie den letzten Punkt: In den Protokollen steht die ID, nicht der komplette Rumpf. Vollständige Anfragen mitzuschreiben ist bequem, füllt die Festplatte und ist datenschutzrechtlich fast immer ein Problem. Der erste Punkt ist ein logischer Kurzschluss, den man erstaunlich oft sieht: Der Server erzeugt den Idempotenzschlüssel selbst.
8:29 Damit ist jede Anfrage neu, und das Verfahren löst genau nichts. Der zweite Punkt ist ein Betriebsrisiko — Wiederholungen ohne Wartezeit verwandeln eine kurze Störung in einen Ausfall, weil alle Clients gleichzeitig nachlegen. Und der vierte ist die unauffällige Variante davon: Gespeicherte Schlüssel ohne Verfallsdatum lassen eine Tabelle wachsen, bis sie irgendwann selbst zum Problem wird.
Übung
8:51 Bringen wir das zusammen. Sie entwerfen jetzt die Fehlerantworten für die Bestellung der Hofkiste — und zwar so, dass die Kunden-App daraus eine sinnvolle Anzeige bauen kann. Das Erfolgskriterium ist dabei bewusst hart formuliert: Die Fälle müssen für eine Maschine unterscheidbar sein, nicht nur für einen Menschen lesbar.
9:09 Drei Fälle, die im Betrieb der Hofkiste täglich vorkommen: Das Lieferfenster ist abgelaufen, das Kistenkontingent ist ausgeschöpft, die Adresse ist ungültig. Ihre Aufgabe ist, für jeden Fall einen eigenen Problemtyp zu vergeben, den passenden Statuscode zu wählen und ein Erweiterungsfeld zu ergänzen, das dem Consumer weiterhilft.
9:28 Das Erfolgskriterium ist bewusst hart formuliert: Die drei Fälle müssen für eine Maschine unterscheidbar sein. Als Erweiterung fangen Sie eine doppelt abgeschickte Bestellung über einen Idempotenzschlüssel ab. Der erste Schritt ist der, über den am längsten diskutiert wird — und das ist gut so. Ist ein ausgebuchtes Lieferfenster ein Konflikt mit dem aktuellen Zustand, also 409?
9:51 Oder eine formal korrekte, fachlich unmögliche Anfrage, also 422? Beide Lesarten sind vertretbar; wichtig ist, dass Sie sich entscheiden und es durchhalten. Der vierte Schritt ist die eigentliche Qualitätsprüfung: Setzen Sie sich in die Rolle der Kunden-App und fragen Sie, ob Sie aus dieser Antwort eine hilfreiche Anzeige bauen könnten.
10:12 Alle drei Punkte laufen auf dasselbe hinaus: Der Consumer muss raten. Wenn alle Fälle 400 liefern, bleibt ihm nur der Text — und Texte zu parsen ist der sicherste Weg, beim nächsten Release zu brechen. Wenn das Erweiterungsfeld in jedem Fehler anders heißt, kann er keine gemeinsame Behandlung bauen. Die Regel dahinter ist einfach: Alles, worauf ein Consumer programmatisch reagieren soll, gehört in ein Feld mit stabilem Namen — nie in Prosa.
Lieber mit Trainer? Dieses Modul ist Teil unserer Team-Schulungen — mit Übungen, Ihrem eigenen Code und Fragen, die ein Video nicht beantwortet. Mehr erfahren →