Abschnitt 11 · Lektion 1
Was ist eine API?
Bis hierhin hat dein Server Seiten ausgeliefert, also HTML, das ein Browser anzeigt. Eine API liefert dieselben Daten an ein anderes Programm, und dieses Programm hat keine Augen. Es braucht keine Überschrift, keine Farbe und keine Reihenfolge, sondern nur die Daten in einer verlässlichen Form.
Dieselben Daten, zwei Verpackungen
import express from "express";
const app = express();
const buecher = [
{ id: 1, titel: "Node in der Praxis", jahr: 2024 },
{ id: 2, titel: "JavaScript von vorn", jahr: 2023 },
];
// Fuer Menschen: eine Seite, die ein Browser anzeigen kann.
app.get("/buecher", (req, res) => {
const zeilen = buecher.map((buch) => `<li>${buch.titel}</li>`).join("");
res.send(`<h1>Buecher</h1><ul>${zeilen}</ul>`);
});
// Fuer Programme: dieselben Daten, ohne jede Gestaltung.
app.get("/api/buecher", (req, res) => {
res.json({ anzahl: buecher.length, daten: buecher });
});
app.listen(3000); Rechts steht die Seite für Menschen. Tipp /api/buecher in die Adresszeile, und dort stehen dieselben
Daten als JSON. Derselbe Bestand, zwei Verpackungen.
Zwei Routen, dieselbe Liste. Die eine baut daraus HTML, die andere gibt sie als JSON heraus. Der
Content-Type sagt, was der Empfänger vor sich hat, und daran hängt alles Weitere.
Eine API rendert nichts. Das ist keine Sparsamkeit, sondern Arbeitsteilung. Wer die Daten bekommt, entscheidet selbst, was daraus wird: eine Webseite, eine App, ein Skript, das nachts eine Statistik rechnet. Sobald du Gestaltung mitschickst, hast du diese Entscheidung für alle getroffen, auch für die, die du noch gar nicht kennst.
Dinge statt Tätigkeiten
Jetzt die Frage, an der sich der Entwurf entscheidet: Wie heißen deine Pfade?
Der naheliegende Weg ist, sie nach dem zu benennen, was sie tun. /buchAnlegen, /buchLoeschen,
/alleBuecher. Das liest sich gut und funktioniert auch, bis die Schnittstelle wächst.
import express from "express";
const app = express();
// Ein Pfad je Taetigkeit. Fuenf Namen, die man kennen muss.
app.get("/alleBuecher", (req, res) => res.json({ anzahl: 4 }));
app.get("/buchLesen", (req, res) => res.json({ id: 2 }));
app.post("/buchAnlegen", (req, res) => res.status(201).json({ id: 5 }));
app.post("/buchAendern", (req, res) => res.json({ id: 2 }));
app.post("/buchLoeschen", (req, res) => res.json({ geloescht: true }));
// Ein Pfad je Ding. Zwei Namen, und die Methode sagt den Rest.
app.get("/buecher", (req, res) => res.json({ anzahl: 4 }));
app.post("/buecher", (req, res) => res.status(201).json({ id: 5 }));
app.get("/buecher/:id", (req, res) => res.json({ id: 2 }));
app.patch("/buecher/:id", (req, res) => res.json({ id: 2 }));
app.delete("/buecher/:id", (req, res) => res.status(204).end());
app.listen(3000); Beide Entwürfe liegen in derselben Datei. Die lesenden Adressen kannst du über die Adresszeile durchgehen, für die schreibenden nimmst du das Terminal:
curl -i -X POST http://localhost:3000/buchAnlegen
curl -i -X POST http://localhost:3000/buecher
curl -i -X DELETE http://localhost:3000/buecher/2
Beide Reihen tun genau dasselbe. Oben stehen fünf Pfade, die man einzeln kennen muss. Unten stehen
zwei, /buecher und /buecher/:id, und die Methode sagt, was damit passieren soll.
Warum das keine Geschmacksfrage ist
Stell dir vor, jemand bekommt deine Schnittstelle vorgelegt und will einen Eintrag löschen. Beim
ersten Entwurf muss er raten oder nachschlagen: Heißt es /buchLoeschen, /loescheBuch oder
/buchEntfernen? Beim zweiten Entwurf weiß er es, ohne zu fragen. Es ist derselbe Pfad wie beim
Lesen, nur mit DELETE davor.
Dazu kommt etwas, das du nicht siehst: Die Methoden haben eine Bedeutung, an die sich andere
Programme halten. Ein GET gilt als ungefährlich, deshalb dürfen Browser und Zwischenspeicher ihn
wiederholen, ohne zu fragen. Wenn dein Löschen als GET /buchLoeschen/2 erreichbar ist, kann ein
Zwischenspeicher es wiederholen, und dann ist der Eintrag weg, ohne dass jemand geklickt hat.
Mehrzahl, Kennung und Beziehungen
Drei Gewohnheiten, mit denen du in der Regel richtig liegst. Sammlungen stehen in der Mehrzahl,
also /buecher und nicht /buch. Ein einzelner Eintrag hängt mit seiner Kennung dahinter, also
/buecher/2, und wie du in Lektion 9.3 gesehen hast, ist die für Express einfach ein Pfadstück.
Und was zu einem Eintrag gehört, wird ein verschachtelter Pfad.
import express from "express";
const app = express();
// Eine Beziehung wird ein verschachtelter Pfad: die Buecher dieses Autors.
app.get("/autoren/:id/buecher", (req, res) => {
res.json({ autor: Number(req.params.id), anzahl: 2 });
});
// Und zwei Faelle, in denen die Regel nicht traegt, weil es kein Ding gibt.
app.get("/suche", (req, res) => {
res.json({ frage: req.query.q, treffer: 1 });
});
app.post("/login", (req, res) => {
res.json({ angemeldet: true });
});
app.listen(3000); Rechts stehen die Bücher des Autors 3. /suche?q=node zeigt die zweite Ausnahme, und für die dritte
brauchst du wieder das Terminal:
curl -i -X POST http://localhost:3000/login
/autoren/3/buecher liest sich von links nach rechts wie ein Satz: die Bücher des Autors mit der
Nummer 3. Das ist der ganze Trick an verschachtelten Pfaden, und mehr als zwei Ebenen braucht man
selten.
Wo die Denkweise aufhört
Die letzten beiden Routen im Beispiel sind keine Dinge. Eine Suche ist eine Frage, und eine Anmeldung ist ein Vorgang. Beide lassen sich in eine Ressource pressen, und beides ergibt dann Pfade, die niemand mehr versteht.
Wenn es kein Ding gibt, benenne ruhig die Tätigkeit. /suche und /login sind gute Namen. Die
Regel ist ein Werkzeug und kein Gesetz, und ein Entwurf, der sie gegen jede Vernunft durchzieht, ist
schlechter als einer, der an zwei Stellen die Ausnahme benennt.
Zum Mitnehmen
Benenne Dinge, nicht Tätigkeiten. Die Methode sagt, was damit passieren soll, und dann muss niemand deine Pfadnamen raten.
Jetzt du
Basis Konto, kostenlosZu dieser Lektion gehört eine Aufgabe. Du schreibst den Code selbst, und nach jedem Lauf sagt dir eine Prüfliste, was schon stimmt.
Dafür brauchst du das Basis Konto. Es kostet nichts, und ein Passwort gibt es auch nicht.
In diesem Kurs läuft dein Code auf einem Server. Dafür hat das Basis Konto 1 Stunde im Monat, mehr Zeit gibt es mit dem Premium Konto.
Was in dieser Lektion steckt
-
Artikel mit 3 Beispielen zum Ausprobieren
Steht hier, ohne Konto lesbar.
-
Aufgabe, dein Code läuft auf einem Server
Öffnet sich mit dem Basis Konto.