Zum Inhalt springen

6.1 Schnittstellen entwerfen: Ressourcen und Datenvertrag

Zu Zen-Modus wechseln

Nach dieser Einheit kannst du:

  • das Ressourcen-Prinzip von REST erklären: Substantiv-URLs, Methoden als Aktionen, Statuscodes als Ergebnis.
  • für eine gegebene Aufgabe die Ressourcen, Endpunkte und Query-Parameter einer API festlegen.
  • Anfrage- und Antwortformate als JSON-Verträge mit Beispielen definieren und als TypeScript-Interfaces festhalten.

Zwei Teams bauen gleichzeitig eine Buffet-App: eines die Oberfläche, eines den Server. Nach zwei Wochen stecken sie die Teile zusammen, und nichts passt. Die Oberfläche erwartet price, der Server schickt priceCents; die Oberfläche fragt /api/getItems, der Server kennt nur /api/items. Beide haben sauber gearbeitet, nur eben an zwei verschiedenen Verträgen.

sequenceDiagram
    accTitle: Zwei Teams ohne gemeinsamen Vertrag
    participant ui as Team Oberfläche
    participant api as Team Server
    ui->>api: GET /api/getItems
    api-->>ui: 404 Not Found
    ui->>api: GET /api/items
    api-->>ui: [{"priceCents": 280}]
    Note over ui: erwartet price, zeigt undefined €

Abb. 6.1: Ohne gemeinsamen Vertrag passen Oberfläche und Server nicht zusammen (eigene Darstellung).

Bisher warst du Konsument fremder Schnittstellen; ab jetzt wechselst du die Seite. Der Lehrplan verlangt, Schnittstellen zur Kommunikation zwischen Anwendungen zu entwerfen und zu implementieren, und die Reihenfolge ist ernst gemeint: erst der Entwurf, dann die Implementierung. Im Bild vom Lokal aus Kapitel 5: Erst wird die Speisekarte geschrieben, dann die Küche eingerichtet. Kapitel 6 entwirft eine vollständige API auf Papier, die ab Kapitel 9 in Next.js wirklich implementiert wird. Diese Einheit legt Ressourcen und Datenformate fest, Einheit 6.2 Fehler, Versionen und die Dokumentation.

  • Ressource: ein Ding, das die API verwaltet, etwa ein Job oder eine Bestellung.
  • Sammlung und Element: /api/jobs ist die Sammlung aller Jobs, /api/jobs/42 ein Element daraus.
  • Query-Parameter: Angaben nach dem ? einer URL, etwa ?state=failed, zum Filtern, Sortieren und Blättern.
  • Datenvertrag: die verbindliche Festlegung, wie Anfrage- und Antwort-Bodys aussehen.
  • ISO 8601: das internationale Format für Datum und Uhrzeit, etwa 2027-03-14T09:31:02Z.

Als Entwurfsstil verwenden wir REST aus Einheit 5.2. REST ist kein Gesetz, sondern eine Sammlung von Konventionen; ihr Wert liegt in der Vorhersehbarkeit: Wer eine REST-API kennt, findet sich in der nächsten sofort zurecht.

REST denkt in Ressourcen: den Dingen, die die API verwaltet. Als durchgehendes Beispiel dieses und der folgenden Kapitel dient eine kleine Render-Farm für Videoaufträge; ihre Ressourcen sind etwa Jobs, Presets und Ergebnisdateien. In den Next.js-Kapiteln wird daraus das Projekt render-farm; in den Übungen wendest du dieselben Prinzipien auf eine andere Aufgabe an, das Schulbuffet. Aus den Ressourcen ergeben sich die URLs, und zwar nach festen Regeln:

  • URLs benennen Ressourcen als Substantive im Plural: /api/jobs, /api/presets.
  • Eine Sammlung ist /api/jobs, ein Element daraus /api/jobs/42.
  • Die Aktion steckt in der HTTP-Methode, niemals in der URL: DELETE /api/jobs/42 statt /api/deleteJob?id=42.
  • Zugehörigkeit darf sich verschachteln: /api/jobs/42/log ist das Log von Job 42. Mehr als eine Ebene Verschachtelung wird schnell unhandlich; dann lieber flach bleiben und filtern.

Damit ergibt sich für eine Ressource das Standard-Quintett:

Methode + PfadBedeutungErfolgsstatus
GET /api/jobsalle Jobs auflisten200
POST /api/jobsneuen Job anlegen201 Created
GET /api/jobs/42einen Job lesen200
PATCH /api/jobs/42einen Job ändern200
DELETE /api/jobs/42einen Job löschen204 No Content

Feinheiten, die eine API professionell machen: POST beantwortet das Anlegen mit 201 und liefert die neue Ressource samt vergebener ID im Body zurück; DELETE liefert 204 ohne Body; ein GET auf eine unbekannte ID liefert 404. Wer diese Konventionen einhält, erspart jedem Konsumenten das Rätselraten.

flowchart LR
    accTitle: Sammlung und Element einer Ressource
    coll["/api/jobs<br/>Sammlung"] -- "GET: auflisten<br/>POST: anlegen (201)" --> c1["alle Jobs"]
    el["/api/jobs/42<br/>Element"] -- "GET, PATCH: 200<br/>DELETE: 204" --> e1["Job 42"]
    el -- "Zugehörigkeit" --> log["/api/jobs/42/log"]

Abb. 6.2: Zwei URLs pro Ressource genügen; was geschieht, sagt die Methode (eigene Darstellung).

Filtern, Sortieren und Blättern laufen über Query-Parameter der Sammlung, nicht über neue Pfade:

GET /api/jobs?state=failed
GET /api/jobs?sort=createdAt&order=desc
GET /api/jobs?limit=20&offset=40

Konkret heißt das: Wer “alle fehlgeschlagenen Jobs” braucht, baut keinen Endpunkt /api/failedJobs, sondern fragt GET /api/jobs?state=failed. So bleibt die API klein, und jeder neue Filter ist nur ein neuer Parameter.

Wo begegnet dir das? In der Adresszeile vieler Online-Shops: Filterst du nach Größe oder Farbe, hängt der Shop Parameter wie ?size=M&color=blue an dieselbe Adresse, statt für jede Kombination eine neue Seite anzulegen.

Auflösung

Zwei Ressourcen: devices und loans. Endpunkte: GET /api/devices, GET /api/devices?available=true, POST /api/loans mit der Geräte-ID im Body (Antwort 201 mit der neuen Ausleihe) und zum Beenden PATCH /api/loans/{id} mit einem Rückgabedatum oder DELETE /api/loans/{id}, je nachdem, ob die Ausleihe für die Statistik erhalten bleiben soll. Nicht RESTful wären /api/lendDevice oder /api/returnDevice.

Die zweite Hälfte des Vertrags sind die Datenformate. Für jede Operation wird festgelegt, wie Anfrage- und Antwort-Body aussehen, und zwar verbindlich und mit Beispielen. Für den Render-Job:

{
"id": 42,
"filename": "intro.mp4",
"preset": "web-1080p",
"state": "running",
"progress": 0.62,
"createdAt": "2027-03-14T09:31:02Z"
}

Beim Anlegen (POST /api/jobs) schickt der Client nur, was er wissen kann:

{ "filename": "intro.mp4", "preset": "web-1080p" }

id, state, progress und createdAt vergibt der Server; das Antwortformat ist wieder der vollständige Job. Diese Trennung von Eingabeformat und Ausgabeformat ist eine bewusste Vertragsentscheidung und gehört dokumentiert.

flowchart LR
    accTitle: Der Client schickt wenig, der Server antwortet vollständig
    input["Eingabe (POST):<br/>filename, preset"] --> server["Server vergibt<br/>id, state,<br/>progress, createdAt"]
    server --> output["Ausgabe (201):<br/>vollständiger Job"]

Abb. 6.3: Eingabe- und Ausgabeformat unterscheiden sich; was der Server vergibt, schickt der Client nicht (eigene Darstellung).

Formatregeln, die sich bewährt haben und in diesem Jahr verbindlich sind:

  • Feldnamen in camelCase, einheitlich über die ganze API.
  • Zeitstempel im ISO-8601-Format als String ("2027-03-14T09:31:02Z", das Z markiert UTC); niemals lokale Formate wie 14.03.2027.
  • Zustandsfelder als dokumentierte Wertemenge (queued | running | done | failed), im Code ein Union Type.
  • IDs sind für den Client undurchschaubare Kennungen; ob Zahl oder String, entscheidet der Anbieter einmal und bleibt dabei.
  • Kein Über-Verschachteln: Antworten so flach wie fachlich möglich.

In TypeScript wird der Vertrag zu Interfaces, die später Client und Server importieren; eine Quelle der Wahrheit statt zweier Abschriften:

export interface Job {
id: number;
filename: string;
preset: string;
state: "queued" | "running" | "done" | "failed";
progress: number;
createdAt: string;
}
export type NewJob = Pick<Job, "filename" | "preset">;

Beispielprojekt: 06_schnittstellen_entwerfen_examples/ex01_job_contract

Pick baut aus einem Interface ein neues mit ausgewählten Feldern; du kennst die Hilfstypen aus Einheit 1.6. Im Beispielprojekt meldet der Compiler einen Fehler, sobald ein Objekt vom Typ NewJob ein Feld id mitschicken will: Der Vertrag steht im Typ.

Wo begegnet dir das? Zeitstempel im ISO-Format siehst du in fast jeder öffentlichen API, etwa bei Open-Meteo aus Aufgabe 05-1a. Weil das Format überall gleich ist, kann jede Programmiersprache es ohne Rätselraten lesen, auch über Zeitzonen hinweg.

Auflösung

Beide Werte sind für Menschen formatiert, nicht für Programme: Ein Preis als Text lässt sich nicht addieren, und 14.03.2027 ist ohne Zeitzone und in einem lokalen Format. Vertragstauglich: "priceCents": 280 als ganze Zahl (keine Rundungsfehler mit Kommazahlen) und "createdAt": "2027-03-14T08:31:00Z" im ISO-8601-Format in UTC. Die schöne Darstellung erledigt die Oberfläche.

  1. Verb in der URL: /api/getItems, /api/deleteJob. Die Aktion gehört in die Methode.
  2. Ein Endpunkt pro Filter: /api/failedJobs statt GET /api/jobs?state=failed; die API wächst unkontrolliert.
  3. Eingabe- und Ausgabeformat gleich gesetzt: Der Client soll id oder createdAt nicht mitschicken; ein eigener Typ wie NewJob macht das sichtbar.
  4. Lokale Formate im Vertrag: "14.03.2027" oder "2,80 €" statt ISO 8601 und ganzer Zahlen.
  5. Zwei Abschriften des Vertrags: Client und Server definieren ihre Interfaces getrennt, und sie laufen auseinander.

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 Beispiele 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.

Du kannst jetzt:

  • das Ressourcen-Prinzip von REST erklären: Substantiv-URLs, Methoden als Aktionen, Statuscodes als Ergebnis.
  • für eine gegebene Aufgabe die Ressourcen, Endpunkte und Query-Parameter einer API festlegen.
  • Anfrage- und Antwortformate als JSON-Verträge mit Beispielen definieren und als TypeScript-Interfaces festhalten.
  • Aufgabe 06-1a - API auf Papier, Stufen Wesentlich_überwiegend und Wesentlich_vollständig
  • REST-Konventionen für Ressourcen, URLs, Methoden und Statuscodes → Microsoft: Web API design best practices; MDN: HTTP response status codes
  • ISO 8601 in JavaScript → MDN: Date.prototype.toISOString()
  • Pick → TypeScript-Handbuch: Utility Types
  • Lehrplanbezug (Schnittstellen entwerfen und implementieren) → Lehrplan der Höheren Lehranstalt für Informationstechnologie, B.2 Medientechnik, 2.1 Softwareentwicklung, IV. Jahrgang (zitiert auf der Kursseite Lehrplan und Ablauf)
  • Compiler-Meldung bei einem zusätzlichen Feld in NewJob → eigener Test mit TypeScript 7.0.2 (Oktober 2026)
  • Abb. 6.1 (zwei Teams ohne Vertrag), Abb. 6.2 (Sammlung und Element), Abb. 6.3 (Eingabe und Ausgabe) → eigene Darstellung, alle als Mermaid-Diagramm
  • Oliver Maurhart (MAO)
  • Michael Gabriel (GAM)

CC-BY-SA

https://qiz.at/rules