Zum Inhalt springen

Aufgabe 09-1a - Die eigene API

Zu Zen-Modus wechseln
  • Du setzt REST-Endpunkte als Route Handlers um, mit den Statuscodes und dem Fehlerformat deiner Dokumentation.
  • Du liest Body und Header einer Anfrage, prüfst die Eingaben und beantwortest kaputte Anfragen mit 400 statt mit einem Serverfehler.
  • Du hältst einen dokumentierten Vertrag verbindlich ein und ziehst die Dokumentation nach, wo die Umsetzung abweichen muss.
  • Du nimmst eine API von außen ab, samt aller dokumentierten Fehlerfälle.

Der Entwurf aus Aufgabe 06-1a wird Wirklichkeit: Du setzt die API der Schulbuffet-Vorbestellung als Next.js-Route-Handler um, genau nach eurem Dokument api.md, und nimmst sie ohne Oberfläche ab (siehe Kapitel Next.js: API und Datenfluss). Die Stufen Wesentlich_überwiegend und Wesentlich_vollständig passen nach Einheit 9.1 (Route Handlers), die PlusPlus Aufgabe nach Einheit 9.2 (Daten lesen, frisch statt eingefroren).

Das Dokument ist bindend: Wo die Umsetzung abweichen muss, änderst du zuerst api.md und trägst die Änderung in einem Abschnitt “Changelog” ein. Die Oberfläche folgt in Aufgabe 09-2a, eine Datenbank in Aufgabe 11a; bis dahin liegen die Daten im Arbeitsspeicher.

Projektordner anlegen siehe https://qiz.at/projektordner

  • Lies vorher kurz https://qiz.at/assignmentsabgabe durch.

  • Nur vollständige Abgaben (siehe https://qiz.at/rules) können positiv bewertet werden.

  • Abgabe- und Testdetails siehe https://qiz.at/assignmentsabgabe

  • Die Übung liegt als Unterordner uebung-09-1a in deinem Jahres-Repository SJ26_27_4AHITM_SEW_<Benutzername>_exercises. Du legst ihn wie in Einheit 8.1 an und arbeitest allein:

    Terminal-Fenster
    npx create-next-app@latest uebung-09-1a --ts --app --biome --no-tailwind --no-src-dir --no-react-compiler --cache-components --import-alias "@/*" --use-npm --yes
  • Kopier euer api.md aus Aufgabe 06-1a (mindestens Stand Wesentlich_vollständig) in den Projektordner. Es ist die Vorgabe für alle Pfade, Felder, Statuscodes und Fehlercodes.

  • Die Rolle wird über den Header x-role nachgestellt (buffet oder student); die echte Anmeldung folgt in Aufgabe 12a.

  • Schriftliche Antworten und die verwendeten curl-Aufrufe stehen in der README.md des Projekts. npm run build muss fehlerfrei durchlaufen, npm run lint ohne Fehler; node_modules/ und .next/ kommen nicht ins Repository. Alle Artikel und Bestellungen sind erfunden.

  • Leg in lib/types.ts die Interfaces für Artikel und Bestellung an, getrennt nach Eingabe- und Ausgabeformat, genau wie in api.md.
  • Leg in lib/store.ts den In-Memory-Speicher an: Funktionen zum Lesen und Anlegen von Artikeln und Bestellungen. Beim Start enthält er mindestens drei Artikel, einer davon mit der Menge 0.
  • GET /api/items liefert das Tagesangebot.
  • POST /api/items legt einen Artikel an. Nur die Rolle buffet darf das; geprüft werden ein nicht leerer Name sowie Preis und Menge als nicht negative ganze Zahlen.
  • POST /api/orders legt eine Bestellung an. Geprüft werden: 1 bis 5 Positionen, jede Menge mindestens 1, jeder Artikel existiert, die verfügbare Menge reicht. Bei Erfolg bucht der Server die Mengen ab, vergibt id, Abholnummer, Status und Zeitstempel und antwortet mit 201 samt Bestellung.
  • Jede Antwort, auch jede Fehlerantwort, entspricht dem Format deiner Dokumentation: Statuscode und Fehler-JSON mit code und message.
  • Lös jede Antwort einmal mit curl aus und trag Aufruf und beobachteten Statuscode in die README ein.

Tipp: Beginn jeden GET, der Daten aus dem Speicher liefert, mit await connection(), wie in Einheit 9.1. Setz try/catch um request.json(), und nimm vom Body nichts als gegeben hin: Er kann gültiges JSON sein und trotzdem null oder ein Objekt ohne die erwarteten Felder. Prüf bei einer Bestellung zuerst alle Positionen und buch erst dann ab.

Vollständig, wenn:

  • npm run build und npm run lint fehlerfrei durchlaufen.
  • die drei Endpunkte für den Erfolgsfall und für jeden dokumentierten Fehlerfall den Statuscode und das Format aus api.md liefern.
  • kaputtes JSON mit 400 im Fehlerformat beantwortet wird, nicht mit 500.
  • eine abgelehnte Bestellung keine Mengen verändert.
  • die README zu jeder Antwort den curl-Aufruf und den beobachteten Statuscode enthält.

Wie unter Allgemein.

Für alle, die in der Einheit mit den Schritten oben fertig sind bzw. optional (= freiwillig), wenn du in der Einheit nicht fertig wirst.

Erweitere (siehe Erweitern in https://qiz.at/rules) den vollständigen Teil der vorherigen Stufe dieses Projekts (ändere oder lösche nur, was für diese Aufgabe unbedingt notwendig ist):

  • GET /api/orders liefert die Bestellliste. Nur die Rolle buffet darf sie lesen.
  • GET /api/orders/[id] liefert eine Bestellung, bei unbekannter ID 404.
  • PATCH /api/orders/[id] ändert den Status in der Reihenfolge open, ready, pickedUp. Nur die Rolle buffet darf das; ein ungültiger Sprung, etwa von open direkt auf pickedUp oder ein zweites Mal auf ready, wird mit 409 im Fehlerformat abgelehnt.
  • Ergänz die README um die curl-Aufrufe für einen ganzen Lebenszyklus: bestellen, fertig melden, abholen, und einen abgelehnten Sprung.

Tipp: Die ID aus dem Pfad ist ein String. Halt die erlaubten Übergänge an einer Stelle fest, etwa als Objekt, das zu jedem Status den einzigen erlaubten Folgestatus nennt; dann ist die Prüfung eine Zeile.

Vollständig, wenn:

  • die drei Endpunkte die Statuscodes und Formate aus api.md liefern, auch für unbekannte ID und falsche Rolle.
  • jeder ungültige Statussprung 409 liefert und die Bestellung unverändert lässt.
  • die README den Lebenszyklus mit den beobachteten Statuscodes zeigt.

Wie unter Allgemein.

Für alle, die in der Einheit mit den Schritten oben fertig sind bzw. optional (= freiwillig), wenn du in der Einheit nicht fertig wirst.

Erweitere (siehe Erweitern in https://qiz.at/rules) den vollständigen Teil der vorherigen Stufe dieses Projekts (ändere oder lösche nur, was für diese Aufgabe unbedingt notwendig ist):

  • DELETE /api/orders/[id] storniert eine Bestellung, aber nur im Status open; sonst 409, bei unbekannter ID 404. Ein Storno gibt die Mengen wieder frei.
  • Schreib ein Abnahmeskript acceptance.sh: eine Shell-Datei, die deine API der Reihe nach mit curl aufruft. Über jedem Aufruf steht als Kommentar der erwartete Statuscode. Das Skript spielt einen ganzen Lebenszyklus durch: Artikel anlegen, bestellen, fertig melden, abholen, Storno-Versuch (muss mit 409 scheitern).
  • Ergänz die Negativ-Abnahme: kaputtes JSON, leere Positionsliste, sechs Positionen, unbekannter Artikel, zu große Menge, doppelter Statuswechsel, falsche Rolle. Jede dokumentierte Fehlerantwort wird einmal beobachtet.
  • Führ die Abnahme gegen den Produktionsbetrieb aus (npm run build, dann npm start) und lies den Build-Bericht: Welches Symbol hat jeder Endpunkt, und warum? Halt das in der README fest.
  • Gleich am Ende Dokumentation und Wirklichkeit ab: Jede Abweichung wird behoben oder als Änderung in api.md mit Changelog-Zeile nachgezogen.

Tipp: curl -s -o /dev/null -w "%{http_code}\n" gibt nur den Statuscode aus. Das Skript läuft in der Git Bash. Ein GET, der im Build-Bericht mit ○ erscheint, ist eingefroren (Einheit 9.2).

Vollständig, wenn:

  • das Storno die drei Fälle (204, 409, 404) richtig beantwortet und die Mengen wieder freigibt.
  • acceptance.sh gegen einen frisch gestarteten Server durchläuft und zu jedem Aufruf den erwarteten Statuscode als Kommentar nennt.
  • die Negativ-Abnahme alle genannten Fälle enthält.
  • kein Endpunkt, der veränderliche Daten liefert, im Build-Bericht mit ○ erscheint, und die README die Symbole begründet.
  • api.md und die Umsetzung übereinstimmen und jede Änderung im Changelog steht.

Wie unter Allgemein.

Für alle, die in der Einheit mit den Schritten oben fertig sind bzw. optional (= freiwillig), wenn du in der Einheit nicht fertig wirst.

Erweitere (siehe Erweitern in https://qiz.at/rules) den vollständigen Teil der vorherigen Stufe dieses Projekts (ändere oder lösche nur, was für diese Aufgabe unbedingt notwendig ist):

  • Setz den Bestellschluss um: Nach 9:00 Uhr lehnt POST /api/orders mit dem Code aus deiner Dokumentation ab. Damit sich das testen lässt, liest der Server die Uhrzeit des Bestellschlusses aus einer Umgebungsvariable.
  • Fremd-Abnahme: Tausch mit dem Team, dessen Entwurf ihr in Aufgabe 06-1a geprüft habt. Du testest deren laufende API, nur mit deren Dokument in der Hand; kein Blick in den Code, keine Rückfragen.
  • Führ ein Abnahmeprotokoll foreign-acceptance.md: geprüfter Fall, erwartetes Verhalten laut Dokument, beobachtetes Verhalten, Befund. Jede Überraschung ist ein Fehler der Dokumentation oder der Umsetzung des anderen Teams; formulier die Befunde wie in Aufgabe 06-1a mit Fundstelle, Kriterium und Vorschlag.
  • Nimm die Befunde zum eigenen Projekt entgegen und behebe mindestens zwei.
  • Beurteile in drei Sätzen: Was hat die Fremd-Abnahme gefunden, was dein eigenes Abnahmeskript nicht fand, und warum ist der fremde Blick hier überlegen?

Tipp: Umgebungsvariablen liest du am Server mit process.env.NAME; sie können fehlen, plane einen Fehlwert ein. Für die Fremd-Abnahme genügt es, wenn das andere Team seinen Server im Schulnetz startet und dir die Adresse nennt.

Vollständig, wenn:

  • der Bestellschluss über die Umgebungsvariable einstellbar ist und beide Fälle (vor und nach dem Schluss) mit curl belegt sind.
  • das Abnahmeprotokoll mindestens sechs Fälle mit erwartetem und beobachtetem Verhalten enthält und die Befunde Fundstelle, Kriterium und Vorschlag nennen.
  • mindestens zwei erhaltene Befunde nachvollziehbar behoben sind.
  • die Beurteilung begründet, warum die Fremd-Abnahme anderes findet als die eigene.

Wie unter Allgemein, dazu foreign-acceptance.md.

  1. Wie kommen die HTTP-Methoden eines Endpunkts in Next.js zustande?
  2. Warum antwortet ein kaputter Request-Body mit 400 und nicht mit 500?
  3. Welche Statuscodes gehören zu: erfolgreich angelegt, erfolgreich gelöscht, unbekannte ID, ungültiger Statuswechsel?
  4. Was bedeutet “die Dokumentation ist bindend”, wenn die Umsetzung abweichen muss?
  5. Warum ist der In-Memory-Speicher nach einem Neustart leer, und warum beginnt ein GET auf diesen Speicher mit await connection()?

Durchschnittlich bis Wesentlich_vollständig: ca. 100 min

  • Oliver Maurhart (MAO)
  • Michael Gabriel (GAM)

CC-BY-SA

https://qiz.at/rules