Kompetenzen Portfolio Referenzen Lebenslauf Blog Termin buchen

Grundlagen der REST-API-Entwicklung

Gepostet von: Felix Dziekan in: Blog am 

Alle bauen inzwischen REST-APIs, was heißt, dass viele Leute ihre erste bauen. Die meisten Tutorials springen sofort zu Routing und Serialisierung. Dort geht die Zeit aber nicht hin.

Die Zeit geht in die Schleife: etwas ändern, einen Request schicken, anschauen, was zurückkam, etwas anderes ändern. Krieg diese Schleife richtig hin, und die Endpunkte sind der leichte Teil. Krieg sie falsch hin, und du kämpfst eine Woche lang gegen dein eigenes Setup.

Also: das brauchst du wirklich, in der Reihenfolge, in der es zählt.

Vier Dinge zum Einrichten, und die Schleife, für die es sie gibt

1. Eine Entwicklungsumgebung, die nicht dein Laptop ist

Eine API ist ein Server plus eine Datenbank plus was auch immer sie sonst anspricht. Das alles kommt in Container, und die Container sind in einer Datei im Repository beschrieben — eine Kollegin bekommt also aus einem git clone und einem Befehl eine identische Umgebung, nicht aus einer Seite README-Anweisungen.

Warum das an erster Stelle steht: Eine API ist viel schwerer zu testen als eine Website. Du kannst nicht draufschauen. Du hängst an exakten Statuscodes, exakten Headern, exaktem JSON. Wenn deine Umgebung sich auf irgendeine subtile Weise von der deiner Kollegin unterscheidet, jagst du diesen Unterschied durch ein Dutzend "warum kriege ich hier 401"-Gespräche.

Mein Setup steht hier im Detail — drei Services, eine Datei, Produktions-Image darunter.

2. Eine IDE, die dein Framework versteht

Kein Editor mit Syntax-Highlighting. Etwas, das von einem Route-Attribut zum Controller springen kann, vom Controller zum injizierten Service und vom Service zu seinem Interface — und das einen Debugger an einen laufenden Request hängen kann.

Für eine API zählt der Debugger mehr als für eine normale Anwendung, weil es keine Seite gibt, auf die man schauen kann. Wenn ein Request das Falsche zurückgibt, hast du die Wahl zwischen Durchsteppen und Raten. Raten dauert jedes Mal länger. Die vollständige Begründung habe ich in einem eigenen Artikel gemacht.

3. Eine Möglichkeit, Requests zu schicken

Du brauchst etwas, das ein POST mit JSON-Body und Auth-Header abfeuern und dir die rohe Antwort zeigen kann. Browser können das nicht, und das ist gut so — eine API, die du komplett aus der Adresszeile bedienen kannst, ist eine API, die alles per GET macht, was ein eigenes Problem ist.

Welchen Client du nimmst, ist eine echte Entscheidung mit echten Kompromissen, und ich habe einen ganzen Artikel geschrieben, der die vier vergleicht, die mir immer wieder begegnen. Die Kurzfassung: Postman, wenn das Team gemischt ist und Nicht-Entwickler beteiligt sind; der eingebaute Client der IDE, wenn alle dieselbe IDE nutzen und du die Requests in git haben willst.

Was du auch wählst, halte die Requests im Repository statt im privaten Workspace von jemandem. Dazu gibt es auch einen Artikel, denn das ist die häufigste Art, wie API-Wissen auf dem Laptop einer Person gefangen bleibt.

4. Test-getrieben, und hier zahlt sich das Setup aus

Das ist die Sache, die verändert hat, wie ich APIs baue: Für einen Endpunkt, den du selbst schreibst, ersetzt der Funktionstest den REST-Client vollständig.

Denk darüber nach, was der Client für dich tut. Er hält eine URL, eine Methode, einen Body und einen Auth-Header, feuert sie ab und zeigt dir die Antwort, damit du entscheiden kannst, ob sie richtig ist. Ein Funktionstest hält exakt dieselben vier Dinge — und trifft die Entscheidung dann automatisch, und zwar für immer:

 

public function testCreateReturnsCreated(): void
{
    $client = static::createClient();
    $client->request('POST', '/api/applications', [], [], [
        'CONTENT_TYPE' => 'application/json',
        'HTTP_AUTHORIZATION' => 'Bearer ' . $this->token(),
    ], json_encode(['title' => 'Backend Developer']));

    $this->assertResponseStatusCodeSame(201);
}

 

Du hättest diesen Request beim Bauen des Endpunkts sowieso fünfzigmal geschickt. Ihn als Test zu schreiben kostet dich beim ersten Mal ein paar Zeilen extra, und von da an ist es ein Tastendruck statt eines Fensterwechsels — und wenn du fertig bist, existiert der Regressionstest schon.

Wenn du den Funktionstest zuerst schreibst, brauchst du für deine eigene API überhaupt keinen externen Client. Für die von jemand anderem willst du weiterhin einen.

Die andere Hälfte davon ist, dass der Test dich zwingt zu entscheiden, was der Endpunkt tut, bevor du ihn schreibst. Welcher Statuscode bei Erfolg? Welche Form hat der Fehler? Was passiert ohne Token? Das sind die Entscheidungen, die jetzt billig und nach drei angebundenen Konsumenten teuer sind.

Mehr dazu, wie ich Funktions- und Unit-Tests aufteile, hier, und die PhpStorm-Verkabelung, die das Ausführen zu einem Rechtsklick macht, hier.

Vier Entscheidungen vor dem ersten Endpunkt

Keine davon dreht sich um Werkzeuge, alle sind später schmerzhaft zu ändern.

Deine Fehlerform. Wähl eine JSON-Struktur für jeden Fehler, den die API zurückgeben kann, und nutz sie überall. Konsumenten schreiben genau einen Fehler-Handler, wenn du sie lässt, oder einen Sonderfall pro Endpunkt, wenn nicht.

Deine Statuscodes. 201 für angelegt, 204 für gelöscht ohne Body, 422 für Validierungsfehler, 401 für "wer bist du" versus 403 für "ich weiß, wer du bist, und nein". Einmal entscheiden und konsistent bleiben. Eine API, die 200 mit {"error": …} zurückgibt, zwingt jeden Client, den Body zu parsen, um herauszufinden, ob es geklappt hat.

Wie Versionierung funktionieren wird. Du brauchst heute vielleicht kein /api/v1, aber entscheide jetzt, wie du eine Breaking Change ausliefern wirst, denn die Antwort "wir sagen es einfach allen" hört in dem Moment auf zu funktionieren, in dem es eine mobile App gibt, die Leute nicht aktualisieren.

Woher die Dokumentation kommt. Aus dem Code erzeugt, idealerweise — Attribute am Controller, die eine OpenAPI-Spezifikation produzieren. Handgeschriebene Doku ist an dem Tag korrekt, an dem sie geschrieben wird, und innerhalb eines Monats falsch.

Der eigentliche Punkt

Das Setup ist kein Overhead, den du hinter dich bringst, bevor die eigentliche Arbeit anfängt. Das Setup ist das, was bestimmt, wie schnell die eigentliche Arbeit geht, denn eine API zu bauen sind ein paar hundert Iterationen derselben kleinen Schleife.

Mach diese Schleife einen Tastendruck lang, und alles andere folgt.

Sie brauchen einen Senior-Entwickler, der liefert?

Über 20 Jahre. Produktionssysteme. Echte Deadlines. Ob Architekt, Entwickler oder DevOps-Engineer — ich habe alle drei Rollen übernommen, oft im selben Projekt. Sparen wir uns den Agentur-Overhead und sprechen direkt.