Start / Seminare / Moderne API-Entwicklung mit REST, OpenAPI und Contract Testing

Modul

HTTP-Semantik korrekt einsetzen

4 Kapitel in diesem Modul-Video · Laufzeit

Vertonung mit synthetischer Stimme · Inhalte redaktionell verantwortet · © 2026 HECKER CONSULTING, alle Rechte vorbehalten

Transkript

Der gesprochene Text dieses Moduls zum Mitlesen, Überfliegen und Durchsuchen. Ein Klick auf einen Zeitstempel springt an die Stelle im Video.

HTTP-Semantik korrekt einsetzen

0:00 HTTP ist über dreißig Jahre alt, und die meisten von uns benutzen davon etwa ein Fünftel. Das ist schade, denn in diesem Protokoll stecken Antworten auf Fragen, die wir in jedem Projekt neu diskutieren: Wie erkennt ein Client, ob er wiederholen darf? Wie verhindert man, dass zwei Leute sich gegenseitig überschreiben? Wie spart man Übertragung, ohne selbst einen Cache zu bauen? In diesem Modul holen wir uns diese Antworten.

0:25 Es ist das technischste Modul des ersten Tages — und das mit dem unmittelbarsten Nutzen im Alltag.

HTTP-Semantik korrekt einsetzen

0:32 Wir gehen in drei Schritten vor. Zuerst die Methoden und ihre Eigenschaften, dann die Statuscodes, die im Alltag wirklich zählen. Danach die Header — Aushandlung von Formaten und Sprachen. Und zum Schluss der Teil, der in den meisten Anwendungen fehlt: Validatoren, bedingte Anfragen und der Schutz gegen konkurrierende Schreibzugriffe.

0:53 Grundlage ist RFC 9110, die aktuelle Fassung der HTTP-Semantik.

Methoden und Statuscodes

0:58 Fangen wir mit den Bausteinen an, die jeder kennt — und deren Eigenschaften trotzdem regelmäßig falsch angenommen werden. Drei Begriffe sind dabei entscheidend: sicher, idempotent und cachebar. Wer sie sauber auseinanderhält, beantwortet damit auch die Frage, wann ein Client eine Anfrage wiederholen darf — und die begegnet uns heute noch mehrfach.

1:19 Zwei Begriffe, die im Alltag den Unterschied machen. Sicher heißt: Die Anfrage liest nur, sie verändert nichts. Idempotent heißt: Dieselbe Anfrage darf gefahrlos wiederholt werden, das Ergebnis bleibt gleich. Warum das zählt, merken Sie im Fehlerfall. Ein Client, dessen Verbindung abbricht, muss entscheiden, ob er es noch einmal versuchen darf. Bei einem GET ist das trivial.

1:42 Bei einem POST kann eine Wiederholung eine zweite Bestellung auslösen. Diese Eigenschaften sind also keine Theorie aus dem RFC, sondern die Grundlage jeder Wiederholungsstrategie. Zwei Dinge lohnt es sich hier zu merken. Erstens die Sonderrolle von POST: Es ist als einzige gängige Methode weder sicher noch idempotent — deshalb braucht gerade POST besondere Vorkehrungen, wenn Wiederholungen möglich sind.

2:08 Darauf kommen wir im nächsten Modul zurück. Zweitens die Fußnote zu PATCH, die viele überrascht: PATCH ist gar nicht in RFC 9110 definiert, sondern in einem eigenen RFC. Und es ist nicht idempotent, jedenfalls nicht automatisch. Wer PATCH benutzt, muss selbst dafür sorgen, dass eine Wiederholung nichts kaputt macht. Zwei Paare sind es, die im Alltag am häufigsten verwechselt werden. 400 gegen 422: Vierhundert heißt, ich verstehe die Anfrage nicht — kaputtes JSON, falscher Typ.

2:38 Vierhundertzweiundzwanzig heißt, ich verstehe sie und lehne sie fachlich ab. Für den Consumer ist das ein gewaltiger Unterschied: Im einen Fall ist sein Code falsch, im anderen die Eingabe des Nutzers. Das zweite Paar ist 401 gegen 403. Einundvierzig heißt, ich weiß nicht, wer du bist; dreiundvierzig heißt, ich weiß es und du darfst trotzdem nicht. Wieder eine völlig andere Reaktion auf Clientseite.

3:04 Der erste Punkt ist das verbreitetste Antimuster überhaupt: alles 200, und der eigentliche Status steht im Rumpf. Das funktioniert, solange nur Ihr eigener Client zuschaut. Sobald ein Monitoring die Fehlerquote messen soll, ein Gateway wiederholen möchte oder ein Cache entscheiden muss — alle sind blind. Der zweite Punkt hat denselben Effekt aus anderer Richtung: Wer POST zum Lesen verwendet, schließt jede Zwischenspeicherung aus.

3:28 Und der dritte weckt buchstäblich Menschen: Fachliche Ablehnungen als 500 zu melden, macht aus einer normalen Nutzereingabe einen Alarm.

Header und Content Negotiation

3:37 Weiter mit den Headern. Sie sind der Teil von HTTP, der am ehesten übersehen wird — dabei steckt hier die gesamte Aushandlung zwischen Client und Server, ohne dass jemand einen Parameter erfinden müsste. Sie sind auch der Grund, warum Sie für Formate, Sprachen und Zwischenspeicherung keine eigenen Parameter erfinden müssen. Das Protokoll hat dafür längst Felder.

3:59 Das Bild dazu ist ein Gespräch, in dem beide Seiten vorher sagen, welche Sprachen sie sprechen. Der Client teilt mit Accept mit, was er verarbeiten kann; der Absender kennzeichnet mit Content-Type, was er mitschickt. Findet der Server nichts Passendes zum Ausliefern, antwortet er mit 406. Kann er den gesendeten Rumpf nicht verarbeiten, antwortet er mit 415.

4:21 Der praktische Nutzen: Sie können ein zweites Format anbieten, ohne einen zweiten Endpunkt zu bauen. Und Sie können ein Format später ablösen, ohne Pfade zu ändern. Achten Sie hier vor allem auf die Symmetrie. Der Client sagt, was er möchte, der Server antwortet und kennzeichnet, was er geliefert hat — inklusive Sprache.

4:41 Das Muster wirkt trivial, hat aber eine Konsequenz, die oft übersehen wird: Die Sprachauswahl braucht keinen Pfad und keinen Parameter. Sie ist im Protokoll bereits vorgesehen. Wer stattdessen die Sprache in die URI schreibt, hat dieselbe Ressource plötzlich unter mehreren Adressen — und damit ein Caching- und ein Verlinkungsproblem, das er sich selbst gebaut hat.

5:02 Hier lohnt ein Alltagsbild: die Paketverfolgung. Sie geben etwas ab, bekommen keinen fertigen Zustellnachweis, sondern eine Sendungsnummer — und schauen später nach. Genau so funktioniert das Muster mit 202. Der Server bestätigt die Annahme, verspricht aber kein Ergebnis, und verweist auf eine Statusressource. Ist der Vorgang fertig, führt ein 303 auf das Ergebnis. Der Gewinn ist doppelt: Der Consumer braucht kein Sonderwissen, nur Verweise.

5:31 Und Ihre Verbindung bleibt nicht offen, bis irgendein Zwischensystem sie nach dreißig Sekunden kappt. Der zweite Punkt ist ein Dauerbrenner in Code-Reviews: Versionierung über selbst erfundene Header. Das Problem ist nicht, dass es nicht funktioniert — es funktioniert. Nur kennt den Header kein Werkzeug, keine Dokumentationsseite und kein Generator. Sie haben etwas gebaut, das nur Ihr Team versteht.

5:55 Der letzte Punkt ist der teuerste im Betrieb: Lange Vorgänge, die die Verbindung offen halten, funktionieren im Test wunderbar und scheitern in Produktion an einem Loadbalancer-Timeout, den niemand auf dem Schirm hatte.

Caching und Nebenläufigkeit

6:09 Jetzt kommt der Teil, den ich für den wertvollsten dieses Moduls halte. Mit einem einzigen Header lösen Sie ein Problem, das sonst eine eigene Sperrlogik erfordert — die verlorene Änderung bei gleichzeitigem Schreiben. Der Aufwand dafür ist überraschend gering: ein Header beim Lesen, ein Header beim Schreiben. Sehen wir uns an, wie beides zusammenspielt.

6:30 Ein Validator ist so etwas wie ein Fingerabdruck des aktuellen Stands. Der Server schickt ihn mit, der Client hebt ihn auf, und bei der nächsten Anfrage legt er ihn wieder vor. Daraus ergeben sich zwei Anwendungen. Beim Lesen spart es Übertragung: Ist der Stand unverändert, kommt nur ein 304 zurück, ohne Rumpf. Beim Schreiben schützt es Ihre Änderung: Passt der Stand nicht mehr, lehnt der Server mit 412 ab. Der eigentliche Gewinn ist, dass Sie dafür keine Sperren im System brauchen.

7:00 Erzählen wir das als Geschichte. Zwei Fahrer öffnen dieselbe Tour, beide bekommen denselben Stand mit dem Kennzeichen v-sieben. Der erste speichert, seine Änderung geht durch. Der zweite speichert — und weil sein Kennzeichen nicht mehr aktuell ist, lehnt der Server ab. Genau darum geht es: Nicht der Zweite gewinnt, sondern der Zweite wird informiert.

7:21 Ohne diese Vorbedingung hätte er die Änderung des Ersten stillschweigend überschrieben, und niemand hätte es gemerkt. Das ist der Unterschied zwischen einem Konflikt und einem Datenverlust. Der Unterschied ist schnell erklärt. Ein starker Validator ändert sich bei jeder Änderung der Repräsentation, ein schwacher darf gleich bleiben, wenn sich nur Unwesentliches ändert — etwa ein Zeitstempel im Rumpf, den niemand liest.

7:47 Für den Schutz beim Schreiben brauchen Sie den starken Vergleich, deshalb vergleicht If-Match stark. Fürs Sparen beim Lesen genügt der schwache. Und ein Hinweis zur Orientierung im Regelwerk: Das Caching selbst steht nicht in RFC 9110, sondern in RFC 9111. Die beiden wurden bewusst getrennt. Der erste Punkt ist ein hübscher Fehler, weil er im Test nie auffällt: Ein ETag aus einem Zeitstempel mit Sekundenauflösung ist innerhalb derselben Sekunde blind.

8:15 Im Testlauf tippen Sie langsam genug, in Produktion nicht. Der zweite Punkt ist noch häufiger — der Server liefert brav ETags, prüft If-Match aber nirgends. Das sieht korrekt aus und schützt nichts. Und der vierte ist eine Angstreaktion, die Leistung kostet: Alles pauschal als nicht cachebar zu markieren, weil man einmal veraltete Daten gesehen hat.

Übung

8:36 Setzen wir das direkt um. Die Situation ist realistisch und unangenehm zugleich: Zwei Fahrer der Hofkiste bearbeiten dieselbe Tour, und einer von beiden soll seine Arbeit nicht verlieren. Sie werden sehen, dass die schwierigste Frage dabei nicht die Technik ist, sondern die Wahl des richtigen Statuscodes. Ihre Aufgabe ist, den Schreibzugriff auf eine Tour so abzusichern, dass der zweite Fahrer mit veraltetem Stand eine klare Absage bekommt statt eines stillen Überschreibens.

9:04 Sie legen fest, woraus das ETag entsteht, stellen den Zugriff auf If-Match um und beantworten den Konfliktfall. Nebenbei begründen Sie, ob hier PUT oder PATCH die richtige Methode ist. Als Erweiterung ergänzen Sie eine bedingte Leseanfrage, die bei unverändertem Stand mit 304 antwortet — dieselbe Mechanik, anderer Zweck.

9:24 Der interessanteste Schritt ist der vierte. 409 und 412 sehen für den Consumer ähnlich aus, meinen aber Verschiedenes: 412 sagt, deine Vorbedingung stimmt nicht mehr — lade neu und versuche es erneut. 409 sagt, dein Wunsch passt fachlich nicht zum aktuellen Zustand, etwa weil die Tour bereits abgeschlossen ist. Im ersten Fall hilft Wiederholen, im zweiten nicht.

9:47 Nehmen Sie sich für diese Unterscheidung Zeit — sie entscheidet darüber, was die App auf der anderen Seite tun kann. Der zweite Punkt ist der, an dem Anwender leiden und den Entwickler selten sehen. Nach einem 412 lädt die App pflichtbewusst neu — und wirft dabei die Eingabe des Fahrers weg. Technisch korrekt, praktisch eine Zumutung. Ein guter Konfliktdialog zeigt beide Stände und lässt wählen.

10:11 Der dritte Punkt ist ein Entwurfsfehler mit spürbarer Folge: Ein ETag über die ganze Collection ändert sich, sobald irgendein Eintrag angefasst wird. Es ist dann formal richtig und praktisch wertlos, weil es nie mehr passt.

Lieber mit Trainer? Dieses Modul ist Teil unserer Team-Schulungen — mit Übungen, Ihrem eigenen Code und Fragen, die ein Video nicht beantwortet. Mehr erfahren →