mitmario.dev

Was ist eine API?

Node.js Sandbox 3 Min Lesezeit 3 BeispieleLektion 1 von 8

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

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.

Fünf Tätigkeiten gegen zwei Pfade
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.

Beziehungen und zwei Ausnahmen
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, kostenlos

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