5.2 HTTP: fetch, REST und der Schnittstellenvertrag
Nach dieser Einheit kannst du:
- Anfragen mit
fetchundasync/awaitstellen,response.okprüfen und die drei Fehlerfälle an der Netzwerkgrenze behandeln. - REST als Architekturstil beschreiben, Ressourcen und Methoden auseinanderhalten und eine fremde API anhand ihrer Dokumentation konsumieren.
- die Schnittstelle als Vertrag zwischen Anbieter und Konsument beschreiben und begründen, warum Vertragsbrüche fremde Programme beschädigen.
Eine Wetter-App zeigt “Villach: undefined °C”. Kein Absturz, keine Fehlermeldung, nur ein undefined. Der Server war gar nicht kaputt: Er hat ehrlich mit 404 geantwortet, weil der Ort falsch geschrieben war. Nur hat der Code nie nachgesehen, was auf dem Bon steht.
flowchart LR
accTitle: Ein 404 wird wie eine erfolgreiche Antwort verarbeitet
req["fetch(.../forecast?city=Vilach)"] --> res["Response 404,<br/>Body: {error: ...}"]
res --> json["response.json()<br/>ohne Prüfung"]
json --> ui["Anzeige:<br/>undefined °C"]
Abb. 5.5: fetch meldet einen 404 nicht als Fehler; wer response.ok nicht prüft, verarbeitet die Fehlerantwort wie Daten (eigene Darstellung).
In Einheit 5.1 hast du HTTP-Nachrichten gelesen und von Hand verschickt. Diese Einheit schreibt sie im Code, mit fetch. Dazu kommen REST, der übliche Baustil für HTTP-Schnittstellen, und der Begriff, der die nächsten Kapitel trägt: die Schnittstelle als Vertrag. Im Bild vom Lokal ist dieser Vertrag die Speisekarte.
Begriffe vorab
Abschnitt betitelt „Begriffe vorab“fetch: die eingebaute Funktion, mit der JavaScript in Browser und Node.js HTTP-Anfragen stellt.- Ressource: ein Ding, das eine API anbietet, etwa ein Job oder ein Benutzer, mit einer eigenen URL.
- Endpunkt: eine Kombination aus Methode und URL, die eine API beantwortet, etwa
GET /api/jobs/42. - REST: ein Architekturstil für HTTP-Schnittstellen, bei dem Ressourcen über URLs und Tätigkeiten über HTTP-Methoden ausgedrückt werden.
- Schnittstellenvertrag: die Zusicherungen einer API über Endpunkte, Datenformate und Fehlerverhalten.
fetch: HTTP aus eigenem Code
Abschnitt betitelt „fetch: HTTP aus eigenem Code“Die eingebaute Funktion fetch stellt Anfragen aus JavaScript, in Browser und Node.js gleich. Sie ist asynchron und liefert Promise<Response>; hier zahlt sich Kapitel 3 direkt aus:
interface Job { id: number; state: "queued" | "running" | "done" | "failed"; progress: number;}
async function loadJob(id: number): Promise<Job> { const response = await fetch(`https://render.example.org/api/jobs/${id}`); if (!response.ok) { throw new Error(`loading job ${id} failed: ${response.status}`); } return (await response.json()) as Job;}Beispielprojekt: 05_http_und_schnittstellen_examples/ex01_fetch_load_job
render.example.org ist eine Beispieladresse, die es nicht gibt; das Beispielprojekt simuliert den Server, damit der Code ohne Netz läuft. Drei Punkte sind hier Handwerksregeln:
fetchscheitert nur bei Netzwerkfehlern. Ein404oder500ist fürfetcheine erfolgreiche Antwort; das Promise wird erfüllt. Die Prüfungif (!response.ok), wahr bei Status 200 bis 299, ist deshalb Pflicht in jedemfetch-Aufruf. Ihr Fehlen ist der häufigste Anfängerfehler mit dieser Funktion.- Zwei
await: eines für die Antwort samt Headern, eines fürresponse.json(), das den Body liest und in ein Objekt umwandelt. - Der Typ ist ein Versprechen an dich selbst.
as Jobbehauptet, dass die API dieses Format liefert; geprüft wird es nicht. Für den Konsum fremder APIs reicht das zunächst, die saubere Prüfung an der Grenze folgt in Kapitel 12.
Daten senden funktioniert über den zweiten Parameter:
const response = await fetch("https://render.example.org/api/jobs", { method: "POST", headers: { "Content-Type": "application/json" }, body: JSON.stringify({ filename: "intro.mp4", fps: 25 }),});Beispielprojekt: 05_http_und_schnittstellen_examples/ex02_fetch_post
JSON.stringify macht aus dem Objekt Text, der Content-Type-Header sagt dem Server, welches Format kommt. Die Gegenrichtung, JSON.parse beziehungsweise response.json(), macht aus Text wieder Objekte. JSON ist damit das Austauschformat in beide Richtungen, das der Lehrplan als strukturiertes Datenformat nennt. Im Beispielprojekt antwortet der simulierte Server mit 201 und dem neu angelegten Job.
Vollständige Fehlerbehandlung unterscheidet drei Fälle, wie an jeder Grenze zu fremden Daten:
- Netz weg:
fetchselbst wirft, etwa bei einer falschen Domain. - Fehlerstatus: Der Server antwortet, aber
response.okistfalse. - Unbrauchbarer Body:
response.json()wirft, weil die Antwort kein gültiges JSON ist.
flowchart LR
accTitle: Die drei Fehlerfälle an der Netzwerkgrenze
request["await fetch(url)"] -- "wirft" --> net["Netz weg"]
request --> ok{"response.ok?"}
ok -- "nein" --> status["Fehlerstatus"]
ok -- "ja" --> json["await response.json()"]
json -- "wirft" --> body["unbrauchbarer Body"]
json --> data["Daten"]
Abb. 5.6: Drei Stellen, an denen eine Anfrage scheitern kann, und nur eine davon meldet fetch selbst (eigene Darstellung).
Eine kleine Hilfsfunktion, die alle drei in einen aussagekräftigen Fehler übersetzt, gehört in jedes Projekt dieses Jahres; in Aufgabe 05-1a baust du sie selbst.
Wo begegnet dir das? In jeder App, die Daten nachlädt: Ein Feed, der “Konnte nicht geladen werden, erneut versuchen?” anzeigt, statt leer zu bleiben, unterscheidet genau diese Fälle.
Auflösung
Der Server antwortet mit 404 und einem Fehler-Body, etwa {"error": "job 99 not found"}. Ohne die Prüfung wird dieser Body als Job zurückgegeben; job.state und job.progress sind undefined. Der Fehler fällt erst viel später auf, etwa als “undefined %” in der Anzeige, weit weg von der eigentlichen Ursache. Mit der Prüfung wirft loadJob sofort loading job 99 failed: 404.
REST: ein Baustil für HTTP-Schnittstellen
Abschnitt betitelt „REST: ein Baustil für HTTP-Schnittstellen“Bisher war HTTP das Transportmittel und JSON das Format. Aber wie ordnet man eine API dahinter sinnvoll? Die mit Abstand häufigste Antwort heißt REST (Representational State Transfer). REST ist kein Standard und keine Bibliothek, sondern ein Architekturstil: eine Sammlung von Prinzipien, die Roy Fielding im Jahr 2000 in seiner Dissertation beschrieben hat. Eine API, die sie einhält, heißt RESTful.
Der Kerngedanke ist einfach: Alles, was die API anbietet, wird als Ressource modelliert (ein Job, ein Benutzer, ein Rezept), jede Ressource hat eine eigene URL, und die HTTP-Methoden aus Einheit 5.1 sagen, was mit ihr geschehen soll:
GET /api/jobs alle Jobs lesenPOST /api/jobs neuen Job anlegenGET /api/jobs/42 einen bestimmten Job lesenPUT /api/jobs/42 Job 42 komplett ersetzenDELETE /api/jobs/42 Job 42 löschenDie URL benennt also das Ding (das Substantiv), die Methode die Tätigkeit (das Verb). Ein häufiger Anfängerfehler ist, das Verb in die URL zu packen (/api/getJob?id=42, /api/deleteJob); RESTful ist das nicht.
flowchart LR
accTitle: In REST benennt die URL das Ding und die Methode die Tätigkeit
method["Methode<br/>= Verb<br/>GET, POST, DELETE"] --> endpoint["DELETE /api/jobs/42"]
url["URL<br/>= Substantiv<br/>/api/jobs/42"] --> endpoint
wrong["✗ /api/deleteJob?id=42<br/>Verb in der URL"]
Abb. 5.7: Methode und URL teilen sich die Arbeit; ein Verb in der URL ist nicht RESTful (eigene Darstellung).
Die sechs Prinzipien
Abschnitt betitelt „Die sechs Prinzipien“Fielding beschreibt REST über sechs Bedingungen (constraints). Fünf sind verpflichtend, eine ist optional.
- Client-Server: Anbieter und Konsument sind getrennt und kennen voneinander nur den Vertrag über die Schnittstelle. Der Client kümmert sich um die Darstellung, der Server um Daten und Logik. Beide können sich unabhängig weiterentwickeln, solange der Vertrag hält.
- Zustandslosigkeit (stateless): Jede Anfrage bringt alles Nötige selbst mit; der Server merkt sich zwischen zwei Anfragen keinen Sitzungszustand. Das ist die Zustandslosigkeit von HTTP aus Einheit 5.1, hier zur Regel erhoben.
- Cachebarkeit (cacheable): Antworten kennzeichnen, ob und wie lange sie zwischengespeichert werden dürfen. Weil
GETDaten nur liest, lässt es sich gefahrlos cachen; das spart Anfragen und macht die API schneller. - Einheitliche Schnittstelle (uniform interface): Alle Ressourcen werden nach demselben Muster angesprochen: URLs als Ressourcen, Standardmethoden, Standard-Statuscodes. Wer eine RESTful API bedienen kann, findet sich in jeder anderen sofort zurecht. Das ist das zentrale Prinzip, das REST seine Wiedererkennbarkeit gibt.
- Schichtensystem (layered system): Zwischen Client und Server dürfen Zwischenschichten liegen (Caches, Lastverteiler, Gateways), ohne dass der Client davon weiß. Er spricht immer nur mit “der API”, nicht mit einem bestimmten Rechner dahinter.
- Code on Demand (optional): Der Server darf ausführbaren Code an den Client nachliefern, etwa JavaScript. Als einzige der sechs Bedingungen ist sie freiwillig; die meisten APIs verzichten darauf.
Auflösung
RESTful: GET /api/students, POST /api/students und DELETE /api/students/7. Gefährlich ist der dritte: Ein GET darf nichts verändern, Browser und Zwischenspeicher rufen GET-Adressen auch von sich aus auf, etwa beim Vorausladen von Links. Ein Löschen über GET kann so ohne Absicht ausgelöst werden.
Fremde APIs konsumieren
Abschnitt betitelt „Fremde APIs konsumieren“Öffentliche APIs gibt es zu fast allem; zum Üben eignen sich etwa Open-Meteo (Wetter, ohne Anmeldung), die PokéAPI oder Test-APIs mit Beispieldaten. Der Arbeitsablauf ist immer derselbe, und er ist eine eigene Kompetenz:
- Dokumentation lesen: Welche Endpunkte gibt es, welche Parameter, welches Antwortformat? Gute API-Dokumentation enthält Beispielanfragen samt Beispielantworten.
- Im Terminal oder Browser ausprobieren, bevor Code entsteht: eine Anfrage von Hand, Antwort ansehen.
- Datenvertrag als Interface festhalten: die Antwortstruktur oder den benötigten Ausschnitt als TypeScript-Interface notieren. Niemand braucht alle 40 Felder; ins Interface kommt, was das Programm verwendet.
- Robust konsumieren:
response.okprüfen, Fehlerfälle behandeln, bei optionalen Feldern?.und??einsetzen.
flowchart LR
accTitle: Vier Schritte, um eine fremde API zu nutzen
docs["1. Doku lesen"] --> try["2. von Hand<br/>ausprobieren"]
try --> contract["3. Interface<br/>festhalten"]
contract --> code["4. robust<br/>konsumieren"]
Abb. 5.8: Erst lesen und ausprobieren, dann den Vertrag festhalten, zuletzt programmieren (eigene Darstellung).
Zwei Realitäten fremder APIs gehören von Anfang an ins Bild. API-Schlüssel: Viele Dienste verlangen einen Schlüssel pro Anfrage; er gehört in eine Konfigurationsdatei, niemals ins Repository. Rate Limits: Zu viele Anfragen in kurzer Zeit führen zu 429 Too Many Requests; die Begrenzung der Gleichzeitigkeit aus Einheit 4.1 ist hier bares Geld.
Wo begegnet dir das? Jede Wetter-, Fahrplan- oder Karten-App greift auf solche APIs zu. Wenn eine kleine App nach einem Update plötzlich keine Daten mehr zeigt, hat oft der Anbieter der API etwas geändert, und damit sind wir beim Vertrag.
Die Schnittstelle als Vertrag
Abschnitt betitelt „Die Schnittstelle als Vertrag“Zum Abschluss der Begriff, der die nächsten Kapitel trägt. Eine Schnittstelle ist mehr als eine erreichbare URL: Sie ist ein Vertrag zwischen Anbieter und Konsument. Im Lokal ist das die Speisekarte: Was darauf steht, bekommt der Gast, egal wie die Küche das Gericht zubereitet. Der Vertrag umfasst:
- die Endpunkte und ihre Methoden: Was kann man tun?
- die Datenformate von Anfrage und Antwort: welche Felder, welche Typen?
- das Fehlerverhalten: welche Statuscodes, welches Fehlerformat?
- die Zusicherungen: Was bleibt stabil, auch wenn intern umgebaut wird?
flowchart LR
accTitle: Anbieter und Konsument kennen nur den Vertrag
provider["Anbieter:<br/>darf intern alles ändern"] --- contract["Vertrag:<br/>Endpunkte, Formate,<br/>Fehler, Zusicherungen"]
contract --- consumer["Konsument:<br/>verlässt sich nur<br/>auf den Vertrag"]
Abb. 5.9: Zwischen Anbieter und Konsument steht nur der Vertrag (eigene Darstellung).
Der Konsument verlässt sich auf diesen Vertrag, ohne das Innenleben des Anbieters zu kennen; der Anbieter darf intern alles ändern, solange der Vertrag hält. Bricht er ihn, etwa durch ein umbenanntes Feld oder einen geänderten Statuscode, gehen fremde Programme kaputt, deren Autorinnen und Autoren er nicht kennt. Deshalb werden Schnittstellen entworfen statt einfach wachsen gelassen; wie, ist Thema von Kapitel 6.
Auflösung
(b) und (d) brechen den Vertrag: Programme, die progress lesen oder auf 404 prüfen, liefern danach undefined bzw. verarbeiten einen leeren Body als Erfolg. (a) ist ein interner Umbau, den kein Konsument bemerkt. (c) erweitert die Antwort nur; Programme, die das neue Feld nicht kennen, ignorieren es. Zusätzliche Felder gelten deshalb meist als verträglich, umbenannte oder entfernte nicht.
Stolperfallen
Abschnitt betitelt „Stolperfallen“response.oknicht geprüft: Ein404oder500wird als Daten weiterverarbeitet; der Fehler zeigt sich erst viel später alsundefined.- Ein
awaitvergessen:response.json()liefert ein Promise; ohneawaitsteht das Promise statt der Daten in der Variablen. as Jobfür eine Prüfung gehalten: Die Typumwandlung behauptet nur; liefert die API etwas anderes, merkt das TypeScript nicht.- Verb in der URL:
/api/deleteJobstattDELETE /api/jobs/42; besonders gefährlich, wenn dabeiGETetwas verändert. - API-Schlüssel im Repository: Was einmal in Git ist, ist auch nach dem Löschen in der Historie.
Zusatzmaterialien
Abschnitt betitelt „Zusatzmaterialien“- MDN: Using the Fetch API - Anfragen, Header, Body und Fehlerbehandlung mit vielen Beispielen.
- MDN: Response.ok - wann
okwahr ist. - Roy Fielding: Representational State Transfer (REST) - das Originalkapitel der Dissertation von 2000, für Neugierige.
- Open-Meteo: API-Dokumentation - eine gut lesbare API-Dokumentation zum Üben, ohne Anmeldung.
Zum Anhören
Abschnitt betitelt „Zum Anhören“Du kannst dir diese Einheit kostenlos mit der Vorlesefunktion deines Browsers oder Betriebssystems vorlesen lassen (etwa „Laut vorlesen” in Edge), ohne Konto und ohne Upload; die Codebeispiele liest du dabei am Bildschirm mit. Freiwillig kannst du mit Google NotebookLM (Google-Konto nötig) aus diesem öffentlichen Text eine gesprochene Zusammenfassung erzeugen, auch auf Deutsch.
Lernergebnisse
Abschnitt betitelt „Lernergebnisse“Du kannst jetzt:
- Anfragen mit
fetchundasync/awaitstellen,response.okprüfen und die drei Fehlerfälle an der Netzwerkgrenze behandeln. - REST als Architekturstil beschreiben, Ressourcen und Methoden auseinanderhalten und eine fremde API anhand ihrer Dokumentation konsumieren.
- die Schnittstelle als Vertrag zwischen Anbieter und Konsument beschreiben und begründen, warum Vertragsbrüche fremde Programme beschädigen.
Passende Übungen
Abschnitt betitelt „Passende Übungen“- Aufgabe 05-1a - API-Konsument, Stufen Wesentlich_vollständig, PlusPlus und MandalorianPlus
Quellen
Abschnitt betitelt „Quellen“fetch,Response,response.ok(Status 200 bis 299) → MDN: Using the Fetch API, Response.ok- REST, sechs Bedingungen, Fielding 2000 → Roy Fielding: Architectural Styles and the Design of Network-based Software Architectures, Kapitel 5; MDN: REST
429 Too Many Requests→ MDN: 429 Too Many Requestsexample.orgals reservierte Beispieladresse → RFC 2606: Reserved Top Level DNS Names- Open-Meteo ohne Anmeldung nutzbar → Open-Meteo: API-Dokumentation; Anfrage selbst getestet (Oktober 2026)
- Verhalten der Beispielprojekte (
404ohne Fehler vonfetch,201beim Anlegen) → eigener Test mit Node.js 24.11.1 und simuliertem Server (Oktober 2026) - Abb. 5.5 (
undefined °C), Abb. 5.6 (drei Fehlerfälle), Abb. 5.7 (URL und Methode), Abb. 5.8 (fremde API in vier Schritten), Abb. 5.9 (Vertrag) → eigene Darstellung, alle als Mermaid-Diagramm
Autoren
Abschnitt betitelt „Autoren“- Oliver Maurhart (MAO)
- Michael Gabriel (GAM)
CC-BY-SA