4. Schnittstellen im Vergleich
Schnittstellen im Vergleich
Abschnitt betitelt „Schnittstellen im Vergleich“In Softwareentwicklung haben Sie REST-Routen gebaut, und die funktionieren. Dieses Kapitel stellt die Frage dahinter: Warum sehen sie so aus? Wer hat entschieden, dass eine Buchung unter /bookings/42 liegt und nicht unter /getBooking?id=42, und was wäre der Unterschied? Welche anderen Arten gibt es, zwei Systeme miteinander reden zu lassen, und wann ist eine davon die bessere?
Am Ende der zwei Wochen haben Sie die Schnittstelle Ihres eigenen Projekts entworfen und begründet, nicht implementiert. Implementiert wird sie in Kapitel 7. Was hier entsteht, ist ein Dokument: eine Liste von Ressourcen, Endpunkten, Statuscodes und Fehlerfällen, dazu ein Eintrag im Entscheidungsprotokoll, warum es so und nicht anders aussieht.
Was eine Schnittstelle leistet
Abschnitt betitelt „Was eine Schnittstelle leistet“Eine Schnittstelle ist ein Versprechen zwischen zwei Systemen, die sich unabhängig voneinander ändern sollen. Das ist die ganze Idee, und daraus folgt alles Weitere: Solange sich beide an das Versprechen halten, darf jede Seite intern umgebaut werden, ohne die andere zu berühren.
Das Unangenehme daran ist, dass ein solches Versprechen schwer zurückzunehmen ist. Eine interne Funktion können Sie umbenennen, der Compiler zeigt Ihnen jede Stelle. Einen veröffentlichten Endpunkt können Sie nicht umbenennen, weil Sie nicht wissen, wer ihn aufruft. Deshalb lohnt sich beim Entwurf die halbe Stunde mehr, die man an einer internen Funktion nie investieren würde.
Vier Fragen taugen als Maßstab, wenn man zwei Entwürfe gegeneinander hält:
- Kopplung: Wie viel muss der Aufrufer über die Interna wissen? Je mehr, desto teurer wird jede spätere Änderung.
- Versionierbarkeit: Lässt sich etwas hinzufügen, ohne bestehende Aufrufer zu brechen? Additive Änderungen sind harmlos, entfernte Felder sind es nie.
- Beobachtbarkeit: Sieht man von außen, was passiert ist? Ein Aufruf, der bei Erfolg und Fehler gleich aussieht, macht jede Fehlersuche zur Rätselstunde.
- Erreichbarkeit: Wer soll sie aufrufen? Ein Browser hat andere Möglichkeiten als ein Server im selben Rechenzentrum, und dieser Unterschied entscheidet später mehr als jede Geschmacksfrage.
REST in der Tiefe
Abschnitt betitelt „REST in der Tiefe“Ressourcen statt Aktionen
Abschnitt betitelt „Ressourcen statt Aktionen“Der zentrale Gedanke hinter REST: Die URL benennt ein Ding, das Verb sagt, was damit geschieht. Nicht die URL beschreibt die Handlung, sondern die HTTP-Methode.
| Statt | Besser | Warum |
|---|---|---|
POST /getBookings | GET /bookings | lesbar, cachebar, im Browser aufrufbar |
POST /createBooking | POST /bookings | die Sammlung nimmt ein neues Element auf |
POST /deleteBooking?id=42 | DELETE /bookings/42 | eindeutig, wiederholbar |
GET /bookingsOfMachine?m=7 | GET /machines/7/bookings | die Beziehung steht im Pfad |
Die Vorteile sind nicht ästhetisch. Ein GET ist zwischenspeicherbar, ein POST nicht. Ein DELETE darf wiederholt werden, bei einem POST /deleteBooking weiß niemand was da beim 2. Mal passiert. Und eine Sammlung unter einem Substantiv lässt sich filtern, sortieren und paginieren, ohne für jede Kombination einen neuen Endpunkt zu erfinden.
Es gibt Fälle, in denen ein Vorgang partout kein Ding ist. Eine Stornierung, ein Versand, eine Freigabe: Das sind Zustandsübergänge mit eigenen Regeln, oft mit eigenen Berechtigungen. Zwei brauchbare Wege stehen offen. Entweder Sie modellieren den Übergang als Unterressource, POST /bookings/42/cancellation, was sich gut anfühlt, sobald der Vorgang eigene Daten hat (Grund, Zeitpunkt, wer). Oder Sie ändern schlicht das Feld, PATCH /bookings/42 mit {"status": "canceled"}, was genügt, solange keine Regeln daran hängen. Was Sie nicht tun sollten, ist beides gleichzeitig anzubieten.
Die Richardson-Reifegrade
Abschnitt betitelt „Die Richardson-Reifegrade“Leonard Richardson hat REST-Schnittstellen in vier Stufen eingeteilt, und diese Einteilung ist bis heute das nützlichste Werkzeug, um eine fremde API einzuschätzen.
| Grad | Merkmal | Praxis |
|---|---|---|
| 0 | ein einziger Endpunkt, alles über POST | RPC über HTTP, kommt tatsächlich recht oft vor |
| 1 | mehrere Ressourcen mit eigenen URLs | erster echter Schritt |
| 2 | HTTP-Methoden und Statuscodes werden benutzt | hier liegt praktisch alles, was „REST-API” heißt |
| 3 | Antworten enthalten Links auf mögliche nächste Schritte (HATEOAS) | selten |
Grad 2 ist das Ziel für Ihr Projekt. Grad 3 sollten Sie kennen und einordnen können: Die Idee ist, dass ein Client nur einen Einstiegspunkt braucht und sich alles Weitere aus den mitgelieferten Links erschließt, so wie ein Mensch eine Website durch Klicken erkundet. In der Praxis setzt sich das kaum durch, weil die Clients trotzdem fest programmiert werden und der zusätzliche Aufwand selten etwas einbringt. Wo es funktioniert, sind lange laufende Systeme mit vielen fremden Aufrufern.
Sicher und idempotent
Abschnitt betitelt „Sicher und idempotent“Zwei Eigenschaften von HTTP-Methoden entscheiden im Betrieb mehr als der Rest dieses Kapitels.
Sicher heißt: Der Aufruf verändert nichts. Idempotent heißt: Zehn identische Aufrufe hinterlassen denselben Zustand wie einer.
| Methode | Sicher | Idempotent | Verwendung |
|---|---|---|---|
GET | ja | ja | lesen |
HEAD | ja | ja | prüfen, ob es etwas gibt |
PUT | nein | ja | vollständig ersetzen |
DELETE | nein | ja | löschen |
PATCH | nein | meist nicht | teilweise ändern |
POST | nein | nein | anlegen, anstoßen |
Die praktische Bedeutung zeigt sich, sobald etwas schiefgeht. Eine Mobilfunkverbindung bricht mitten in der Anfrage ab, und der Client weiß nicht, ob der Server sie bekommen hat. Bei PUT und DELETE kann er einfach nochmal senden. Bei POST darf er das nicht, weil sonst zwei Buchungen entstehen. Genau dieses Problem und seine Lösung über Idempotenzschlüssel behandelt Kapitel 7.
Statuscodes sind Teil des Vertrags
Abschnitt betitelt „Statuscodes sind Teil des Vertrags“Der Statuscode ist die erste Information, die jeder Aufrufer auswertet, oft ohne den Rumpf überhaupt anzusehen. Diese Auswahl reicht für Ihr Projekt:
| Code | Bedeutung | Typischer Fall |
|---|---|---|
| 200 | Erfolg mit Inhalt | GET, PATCH |
| 201 | angelegt, Location zeigt darauf | POST auf eine Sammlung |
| 204 | Erfolg ohne Inhalt | DELETE |
| 400 | Anfrage ist syntaktisch kaputt | ungültiges JSON |
| 401 | nicht angemeldet | Token fehlt oder ist abgelaufen |
| 403 | angemeldet, aber nicht berechtigt | fremde Buchung ändern |
| 404 | gibt es nicht | falsche ID |
| 409 | Konflikt mit dem aktuellen Zustand | Zeitfenster schon belegt |
| 422 | verstanden, aber fachlich unzulässig | Ende liegt vor Beginn |
| 429 | zu viele Anfragen | Ratenbegrenzung, Kapitel 7 |
| 500 | Fehler auf dem Server | unerwartete Ausnahme |
Der Unterschied zwischen 401 und 403 ist der am häufigsten verwechselte: 401 fragt „Wer sind Sie?”, 403 sagt „Sie dürfen das nicht.” Beim ersten hilft eine Anmeldung, beim zweiten nicht.
Ebenfalls verbreitet und ebenso falsch ist die Antwort 200 OK mit {"error": "..."} im Rumpf. Damit kann kein Aufrufer mehr zwischen Erfolg und Fehler unterscheiden, ohne den Rumpf zu interpretieren, und jede Zwischenstation hält den Fehler für ein gültiges Ergebnis und speichert ihn womöglich zwischen.
PUT gegen PATCH
Abschnitt betitelt „PUT gegen PATCH“PUT ersetzt die Ressource vollständig: Was Sie senden, ist danach der komplette Inhalt. Ein weggelassenes Feld ist damit gelöscht. PATCH überträgt nur die Änderung. Der übliche Fehler ist ein PUT, das sich wie ein PATCH verhält, also weggelassene Felder unverändert lässt. Das ist nicht schlimm, solange es dokumentiert ist, und ein Problem, sobald jemand die Dokumentation für bare Münze nimmt.
Wenn zwei gleichzeitig ändern
Abschnitt betitelt „Wenn zwei gleichzeitig ändern“Zwei Personen öffnen dieselbe Buchung, beide ändern etwas, beide speichern. Die zweite Änderung überschreibt die erste kommentarlos. Dieses Lost Update ist kein exotischer Randfall, sondern passiert in jedem System mit mehr als einem Benutzer.
HTTP hat dafür eine Antwort. Der Server schickt bei jeder Antwort einen ETag, eine Kennung des aktuellen Standes. Wer ändern will, schickt sie in If-Match mit. Passt sie nicht mehr, antwortet der Server mit 412 oder 409, statt zu überschreiben.
sequenceDiagram participant A as Person A participant S as Server participant B as Person B A->>S: GET /buchungen/42 S->>A: 200, ETag "v7" B->>S: GET /buchungen/42 S->>B: 200, ETag "v7" A->>S: PATCH /buchungen/42, If-Match "v7" S->>A: 200, neuer ETag "v8" B->>S: PATCH /buchungen/42, If-Match "v7" S->>B: 412 Precondition Failed
Person B bekommt damit die Chance, die fremde Änderung anzusehen, statt sie zu vernichten. Dieselben Header dienen in Kapitel 7 auch dem Caching, was kein Zufall ist: Beides beantwortet die Frage „Ist das noch derselbe Stand?”.
JSON und seine Grenzen
Abschnitt betitelt „JSON und seine Grenzen“JSON kann Zeichenketten, Zahlen, Wahrheitswerte, Listen und Objekte. Alles andere ist Vereinbarung, und genau dort entstehen Fehler zwischen zwei Systemen.
Datum und Zeit gehören in ISO 8601 mit Zeitzone: 2026-03-12T14:30:00+01:00. Ein "12.03.2026" ist keine Zeitangabe, sondern eine Darstellung; wie sie aussieht, entscheidet das Frontend nach der Sprache des Benutzers (Kapitel 12).
Geldbeträge gehören nicht in Gleitkommazahlen. 0.1 + 0.2 ergibt in JavaScript 0.30000000000000004, und das ist kein Ausrutscher, sondern die Binärdarstellung. Üblich sind Ganzzahlen in der kleinsten Einheit, also Cent, oder eine Zeichenkette mit fester Nachkommastellenzahl.
Große Zahlen überschreiten irgendwann den Bereich, in dem JavaScript ganze Zahlen genau darstellt (etwa 9 Billiarden). Datenbank-IDs, die dort hineinlaufen, werden beim Einlesen still gerundet. Deshalb werden lange IDs als Zeichenkette übertragen.
Warum es SOAP gibt
Abschnitt betitelt „Warum es SOAP gibt“Ende der Neunzigerjahre stand die Frage im Raum, wie Systeme unterschiedlicher Hersteller über Firmengrenzen hinweg miteinander reden. Die Antwort war ein vollständig spezifiziertes Protokoll auf XML-Basis, das unabhängig vom Transportweg funktioniert und alles mitbringt, was ein Unternehmen verlangt: einen maschinenlesbaren Vertrag, formale Typen, Signaturen, Verschlüsselung, garantierte Zustellung, verteilte Transaktionen.
Das klingt nach Vergangenheit und ist es nicht. SOAP läuft heute in Banken, Versicherungen, Behörden und ERP-Systemen, und wer nach der Schule in einem dieser Bereiche arbeitet, trifft darauf. Eine Schnittstelle, die seit 2006 stabil läuft und deren Vertrag von einem Gesetz abgeleitet ist, wird nicht ausgetauscht, weil es etwas Moderneres gibt.
Aufbau einer Nachricht
Abschnitt betitelt „Aufbau einer Nachricht“Jede SOAP-Nachricht steckt in einem Envelope mit optionalem Header und verpflichtendem Body.
<?xml version="1.0" encoding="UTF-8"?><soap:Envelope xmlns:soap="http://www.w3.org/2003/05/soap-envelope"> <soap:Header> <wsse:Security xmlns:wsse="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd"> <wsse:UsernameToken> <wsse:Username>workshop</wsse:Username> <wsse:Password Type="...#PasswordDigest">3f9a...</wsse:Password> </wsse:UsernameToken> </wsse:Security> </soap:Header> <soap:Body> <ns:CreateBooking xmlns:ns="https://demo.example.at/workshop"> <ns:MachineId>7</ns:MachineId> <ns:Start>2026-03-12T14:30:00+01:00</ns:Start> <ns:End>2026-03-12T16:00:00+01:00</ns:End> </ns:CreateBooking> </soap:Body></soap:Envelope>Fehler haben eine eigene, festgelegte Form, den Fault:
<soap:Body> <soap:Fault> <soap:Code><soap:Value>soap:Sender</soap:Value></soap:Code> <soap:Reason><soap:Text xml:lang="en">Time slot already booked</soap:Text></soap:Reason> </soap:Fault></soap:Body>Beachten Sie den Unterschied zu REST: Der Fehler steckt im Rumpf, nicht im Statuscode. SOAP benutzt HTTP als Transportmittel und interessiert sich nicht dafür, was HTTP selbst über den Erfolg meint. Genau deshalb funktioniert SOAP auch über andere Transportwege wie SMTP oder Nachrichtenwarteschlangen.
Von Hand ausprobieren lässt sich das mit curl, und genau das sollten Sie einmal getan haben:
curl -X POST https://dienst.example.at/service \ -H "Content-Type: application/soap+xml; charset=utf-8" \ --data @request.xmlWSDL: der Vertrag als Datei
Abschnitt betitelt „WSDL: der Vertrag als Datei“Die WSDL (Web Services Description Language) beschreibt maschinenlesbar, welche Operationen es gibt, welche Typen sie erwarten, welche Fehler auftreten können und unter welcher Adresse der Dienst liegt. Die Typen selbst stehen als XML-Schema drin, mit Pflichtfeldern, Wertebereichen und Musterprüfungen.
Der praktische Effekt ist Codegenerierung. Aus der WSDL erzeugt ein Werkzeug fertige Klassen für Client und Server, in Java, C# oder TypeScript. Der Aufruf sieht danach aus wie ein gewöhnlicher Methodenaufruf, und der Compiler prüft die Typen. Diesen Komfort hat die REST-Welt lange nicht gehabt und über OpenAPI nachgebaut.
Die WS-Familie
Abschnitt betitelt „Die WS-Familie“Um SOAP herum ist eine Reihe von Zusatzstandards entstanden. Drei sollten Sie einordnen können:
WS-Security signiert und verschlüsselt einzelne Teile der Nachricht. Der Unterschied zu TLS ist der entscheidende Punkt und lohnt eine eigene Bemerkung: TLS schützt die Leitung zwischen zwei Punkten. Sobald die Nachricht bei einer Zwischenstation ankommt, liegt sie dort im Klartext. WS-Security schützt die Nachricht selbst, über beliebig viele Zwischenstationen hinweg, und die Signatur bleibt auch nach der Zustellung prüfbar. In einer Kette aus fünf Systemen mit unterschiedlichen Betreibern ist das ein anderer Anspruch als „die Verbindung ist verschlüsselt”.
WS-ReliableMessaging garantiert Zustellung und Reihenfolge, auch wenn zwischendurch etwas ausfällt.
WS-AtomicTransaction erlaubt Transaktionen über mehrere Dienste hinweg, mit gemeinsamem Bestätigen oder Zurückrollen.
REST gegen SOAP
Abschnitt betitelt „REST gegen SOAP“| Kriterium | REST | SOAP |
|---|---|---|
| Vertrag | OpenAPI, optional, oft nachträglich | WSDL, verpflichtend, Teil des Dienstes |
| Typsicherheit | schwach, JSON kennt wenige Typen | stark, XML-Schema mit Wertebereichen |
| Werkzeuge | Browser, curl, jede Bibliothek | Generatoren, spezialisierte Werkzeuge |
| Nachrichtengröße | klein | groß, XML mit Namensräumen |
| Fehlermodell | HTTP-Statuscode plus Rumpf | Fault im Rumpf, HTTP-Status egal |
| Sicherheit | Transportebene (TLS) | zusätzlich Nachrichtenebene (WS-Security) |
| Cachebarkeit | eingebaut über HTTP | praktisch keine |
| Lernkurve | flach | steil |
| Verbreitung heute | Standard im Web | Bestand in Unternehmen und Verwaltung |
SOAP ist die sachlich bessere Wahl, wenn Nachrichten über mehrere Zwischenstationen hinweg signiert und nachweisbar bleiben müssen, wenn ein formaler Vertrag mit Codegenerierung gefordert ist, wenn verteilte Transaktionen gebraucht werden oder wenn die Gegenstelle es schlicht vorschreibt. Für eine Webanwendung mit einem Browser als Hauptaufrufer trifft davon selten etwas zu, dafür stören Nachrichtengröße und fehlendes Caching sofort.
Weitere Paradigmen zur Einordnung
Abschnitt betitelt „Weitere Paradigmen zur Einordnung“RPC (Remote Procedure Call) ist der älteste Gedanke: Ein Aufruf soll aussehen wie ein lokaler Funktionsaufruf. Der Reiz ist offensichtlich, die Schwäche auch: Ein Netzwerkaufruf ist eben kein lokaler Aufruf, er kann langsam sein, verloren gehen oder halb ankommen, und wer das vergisst, baut Systeme, die im Labor laufen und im Betrieb nicht.
gRPC ist die aktuelle Ausprägung davon: Nachrichten in Protobuf, also binär und kompakt, Transport über HTTP/2, Vertrag in einer .proto-Datei, aus der Clients und Server generiert werden. Stark im Verkehr zwischen Diensten im selben Rechenzentrum, weil klein, schnell und typsicher, mit Streaming in beide Richtungen. Schwach im Browser, der nicht direkt gRPC sprechen kann und einen Übersetzungs-Proxy braucht.
GraphQL dreht die Verantwortung um: ein einziger Endpunkt, und der Client beschreibt in einer Abfragesprache, welche Felder er braucht. Damit verschwinden zwei bekannte Probleme, nämlich zu viele gelieferte Felder und zu viele nötige Aufrufe. Dafür entstehen neue: Das HTTP-Caching fällt weg, weil alles über einen POST-Endpunkt läuft; eine Ratenbegrenzung nach Anfragen ergibt keinen Sinn mehr, wenn eine einzelne Abfrage beliebig teuer sein kann, weshalb Kosten- und Tiefengrenzen nötig werden; und im Resolver entsteht das N+1-Problem fast von selbst, gegen das man dann Sammelabfragen einbaut. Für ein Schulprojekt mit einem Frontend ist der Aufwand selten gerechtfertigt.
Für Benachrichtigungen in die Gegenrichtung gibt es drei Bauformen: Webhooks (fremdes System ruft Ihre URL auf, wenn etwas passiert), Server-Sent Events (eine offene Verbindung, über die der Server Ereignisse schickt) und WebSockets (beide Seiten dürfen jederzeit senden). Der Reihe nach steigt die Leistungsfähigkeit und der Aufwand; für „Buchung wurde bestätigt” genügt fast immer die einfachste Variante.
| Paradigma | Passt zu |
|---|---|
| REST | Webanwendungen, öffentliche Schnittstellen, alles mit Browser |
| SOAP | Unternehmen und Verwaltung, formale Verträge, Nachrichtensicherheit |
| gRPC | Dienst zu Dienst, hohe Frequenz, interne Systeme |
| GraphQL | viele verschiedene Clients mit unterschiedlichem Datenbedarf |
| WebSockets, SSE | laufende Aktualisierung, Chat, Live-Ansichten |
Vertrag zuerst oder Code zuerst
Abschnitt betitelt „Vertrag zuerst oder Code zuerst“Bei Code zuerst entsteht die Schnittstelle beim Implementieren, die Beschreibung wird daraus erzeugt. Das ist schnell und führt dazu, dass die Beschreibung beschreibt, was zufällig gebaut wurde.
Bei Vertrag zuerst schreiben Sie zuerst die Beschreibung, und beide Seiten bauen dagegen. Das kostet am Anfang mehr und zahlt sich in genau der Situation aus, um die es im nächsten Kapitel geht: Wenn Frontend und Backend getrennte Anwendungen sind, womöglich von verschiedenen Personen gebaut, dann kann das Frontend gegen einen aus der Beschreibung erzeugten Mock arbeiten, während das Backend noch entsteht. Ohne Vertrag wartet eine Seite auf die andere.
OpenAPI ist für REST das, was WSDL für SOAP ist, mit einem Unterschied: Es ist freiwillig. Erzeugen lassen sich daraus typisierte Clients, Server-Gerüste, Dokumentationsseiten und Testfälle.
openapi: 3.1.0info: title: Workshop Booking version: 1.0.0paths: /machines/{id}/bookings: get: summary: Bookings of a machine within a time range parameters: - { name: id, in: path, required: true, schema: { type: integer } } - { name: from, in: query, schema: { type: string, format: date } } - { name: to, in: query, schema: { type: string, format: date } } responses: "200": description: List of bookings content: application/json: schema: type: array items: { $ref: "#/components/schemas/Booking" } "404": { description: Machine unknown }components: schemas: Booking: type: object required: [id, machineId, start, end, status] properties: id: { type: integer } machineId: { type: integer } start: { type: string, format: date-time } end: { type: string, format: date-time } status: { type: string, enum: [planned, confirmed, canceled] }Diese Datei gehört ins Repository und wird ab jetzt mitgepflegt. In Kapitel 7 kommt die Vertragsprüfung dazu, die im Build feststellt, ob die Implementierung noch zur Beschreibung passt.
Entwurf für das eigene Projekt
Abschnitt betitelt „Entwurf für das eigene Projekt“-
Substantive sammeln. Nehmen Sie die Domänenskizze aus Kapitel 1. Jede Entität ist ein Kandidat für eine Ressource. Nicht jede wird eine: Was nie einzeln adressiert wird, bleibt ein Feld.
-
Sammlungen und Unterressourcen festlegen.
/machines,/machines/7,/machines/7/bookings. Beziehungen werden zu Pfaden, wenn sie das Lesen vereinfachen. -
Operationen zuordnen. Für jede Ressource entscheiden, welche Methoden es gibt und wer sie aufrufen darf. Die Spalte „wer darf” ist der Vorgriff auf Kapitel 8 und deckt oft auf, dass eine Rolle im Datenmodell fehlt.
-
Sonderfälle als Zustandsübergänge modellieren, statt Verben in die URL zu schreiben.
-
Fehlerfälle festlegen, bevor implementiert wird: Welcher Code bei welcher Situation, mit welchem Rumpf. Ein einheitliches Fehlerformat kommt in Kapitel 7.
-
In OpenAPI schreiben und im Repository ablegen. Danach der Eintrag im Entscheidungsprotokoll: welches Paradigma, warum, welche Alternative verworfen.
So sieht das Ergebnis für einen Ausschnitt aus:
| Methode und Pfad | Zweck | Erfolg | Fehler |
|---|---|---|---|
GET /machines | Liste, filterbar | 200 | 401 |
GET /machines/{id} | eine Maschine | 200 | 404 |
GET /machines/{id}/bookings | Belegung im Zeitraum | 200 | 404 |
POST /bookings | Buchung anlegen | 201 mit Location | 400, 409 belegt, 403 ohne Einschulung |
PATCH /bookings/{id} | Zeit ändern | 200 | 403, 409, 412 |
POST /bookings/{id}/cancellation | stornieren mit Grund | 201 | 403, 409 bereits storniert |
An dieser Tabelle sieht man den Wert des Entwurfs vor der Implementierung: Die Zeile mit 403 ohne Einschulung ist eine fachliche Regel, die im Domänenmodell aus Kapitel 1 steckt und die man beim Drauflosprogrammieren typischerweise erst bemerkt, wenn das Formular schon steht.
Häufige Stolperfallen
Abschnitt betitelt „Häufige Stolperfallen“- Verben in URLs wie
/getUseroder/createOrder, dazu immer Statuscode 200. Damit ist HTTP nur noch Transportweg, und alle eingebauten Vorteile sind verschenkt. - Fehler als 200 mit
error-Feld. Kein Aufrufer kann mehr unterscheiden, Zwischenstationen halten den Fehler für ein Ergebnis. - Alles über
POST, weil es einfacher ist. Cachebarkeit und Wiederholbarkeit gehen dabei verloren, und zwar ohne Warnung. GETmit Nebenwirkung. Funktioniert, bis ein Crawler, ein Prefetch oder ein Virenscanner vorbeikommt.- 401 und 403 verwechseln. Der Client versucht dann eine erneute Anmeldung bei einem Berechtigungsproblem und kommt in eine Schleife.
- Datum als deutsche Zeichenkette, Geld als Gleitkommazahl. Beides fällt erst auf, wenn zwei Systeme unterschiedlicher Meinung sind.
- SOAP mit „veraltet” abtun, ohne den Vertragsgedanken verstanden zu haben. Die Frage in der Prüfung ist nicht, ob Sie SOAP mögen.
- GraphQL wählen, weil es modern klingt, und dann Caching, Ratenbegrenzung und Autorisierung neu erfinden.
- Die OpenAPI-Datei nach dem Entwurf nicht mehr anfassen. Eine Beschreibung, die nicht zur Implementierung passt, ist schlechter als keine.
Lernergebnisse
Abschnitt betitelt „Lernergebnisse“- Erklären: die Idee der Ressourcenorientierung erklären und einen aktionsorientierten Entwurf in einen ressourcenorientierten überführen.
- Erklären: die Richardson-Reifegrade benennen und eine fremde Schnittstelle darin einordnen.
- Erklären: sichere und idempotente Methoden unterscheiden und die Folgen für Wiederholungen und Caching begründen.
- Anwenden: Statuscodes sachgerecht wählen, insbesondere 400, 401, 403, 404, 409 und 422 auseinanderhalten.
- Erklären: das Lost-Update-Problem beschreiben und die Lösung über
ETagundIf-Matchdarstellen. - Erklären: Aufbau einer SOAP-Nachricht beschreiben und die Rolle von WSDL und WS-Security erklären, insbesondere den Unterschied zwischen Transport- und Nachrichtensicherheit.
- Analysieren: REST, SOAP, gRPC und GraphQL anhand von Kriterien gegenüberstellen.
- Beurteilen: die Paradigmenwahl für das eigene Projekt begründen und die Zielkonflikte benennen.
- Beurteilen: die Grenzen von JSON als Datenvertrag einschätzen und für Datum, Geld und große Zahlen tragfähige Festlegungen treffen.
- Erschaffen: eine Schnittstelle aus dem Domänenmodell ableiten und als OpenAPI-Beschreibung dokumentieren.
Arbeit am Jahresprojekt
Abschnitt betitelt „Arbeit am Jahresprojekt“- Endpunktliste des eigenen Projekts als Tabelle: Methode, Pfad, Zweck, Erfolgs- und Fehlercodes, erlaubte Rollen.
- Vollständige OpenAPI-Beschreibung der geplanten Schnittstelle im Repository, mit Schemata für die wichtigsten Ressourcen.
- Festlegungen zu Datum, Zahlen und IDs, schriftlich in
docs/architektur.md. - Eintrag im Entscheidungsprotokoll mit der Begründung der Paradigmenwahl und der verworfenen Alternative.
Passende Übungen
Abschnitt betitelt „Passende Übungen“- Aufgabe 13 - SOAP von Hand: eine Anfrage bauen und die WSDL lesen
- Aufgabe 14 - Reifegrad-Analyse einer fremden API
- Aufgabe 15 - Ressourcenschnitt für das eigene Projekt
- Aufgabe 16 - OpenAPI schreiben und Client generieren