Begriff
API Versioning
Warum wichtig?
Dieser Begriff ist ein Knoten im SengakujiWorks-Wissensnetz. Nutze Level 0 für die erste Einordnung, Level 1 für Praxis, Level 2 für technische Struktur und Level 3 für Grenzen, Fallstricke und Expertenkontext.
Wenn du eine Webseite änderst, sehen alle Nutzer sofort die neue Version.
Bei einer API ist das gefährlich.
Tausende Apps verlassen sich darauf, dass die Antwort genau so aussieht wie gestern.
Wenn du das Feld address in address_lines umbenennst, stürzen all diese Apps ab. Das nennt man einen Breaking Change.
API Versioning ist die Strategie, Änderungen einzuführen, ohne alte Apps zu zerstören.
Du bietest einfach zwei Versionen an:
v1: Die alte (läuft weiter für alte Apps).v2: Die neue (für neue Features). So haben Entwickler Zeit, umzusteigen.
Merksatz: Management verschiedener Zustände einer Schnittstelle, um Weiterentwicklung zu ermöglichen, während die Abwärtskompatibilität für bestehende Konsumenten gewahrt bleibt.
Es gibt drei Hauptmethoden ("The Great Debate"):
- URI Path Versioning (Der Standard):
GET https://api.example.com/v1/usersEinfach, explizit, caching-freundlich. Aber "v1" ist technisch keine Ressource. - Query Parameter:
GET https://api.example.com/users?version=2Simpel, aber URLs werden hässlich. - Header Versioning (Content Negotiation):
Accept: application/vnd.example.v1+jsonDas "korrekte" REST-Vorgehen. Die URL (/users) bleibt gleich (Ressource ist stabil), nur die Repräsentation ändert sich. Aber schwerer zu testen im Browser.
Meistens gewinnt Methode 1 (URI Path) wegen der Einfachheit (DX - Developer Experience).
1. Stripe's "Date-Based" Versioning
Stripe gilt als Gold-Standard.
Sie versionieren per Datum: Stripe-Version: 2023-10-16.
Intern haben sie einen einzigen Code-Branch (den neuesten).
Wenn ein Request mit Version 2022-01-01 kommt, durchläuft er eine Kette von Veränderern (Response Transformers).
Der Code produziert die 2023-Antwort -> Transformer rechnet zurück auf 2022-Format -> Transformer rechnet zurück auf 2021-Format -> Antwort an User.
Das hält den Core sauber, macht aber die Infrastruktur extrem komplex ("Middleware Hell").
2. Evolution vs. Versioning (GraphQL)
In GraphQL gilt Versioning als Anti-Pattern.
Statt v2 nutzt man Evolution.
Man markiert alte Felder als @deprecated und fügt neue Felder hinzu.
Da der Client explizit fragt ({ name }), bricht nichts, wenn man new_name hinzufügt.
Man überwacht die Logs: Wenn niemand mehr name abfragt (nach 1 Jahr), löscht man es ("Field Pruning").
3. Sunset Policy
Eine Version ewig zu hosten ist teuer.
Eine gute API hat eine Sunset Policy:
"Version v1 wird am 01.01.2026 abgeschaltet. Support endet 6 Monate vorher."
Dies muss im Header kommuniziert werden (Sunset: <Date>).
Semantic Versioning in APIs (SemVer vs. Realität)
Oft wird behauptet, REST APIs sollten Semantic Versioning (Major.Minor.Patch) nutzen, wie npm-Pakete (v1.2.5). In der Praxis scheitert dies wegen der DX (Developer Experience).
Ein URL-Pattern wie /v1.2/users führt zu endlosen Routing-Aliasing-Problemen im Backend. Stattdessen nutzen Heavy-Duty-APIs meist nur die Major-Version in der URL (/v1).
Changes, die Minor oder Patch abdecken würden, müssen zwingend nicht-brechend abwärtskompatibel gebaut werden (z. B. Hinzufügen optionaler Felder). Brüche (Major) passieren extrem selten und bedeuten einen enormen Migrationsaufwand auf Kundenseite.
API Gateways und Gateway Routing
Wo entscheidet man, welcher Code bei /v1 oder /v2 ausgeführt wird?
Schlecht: Ein gigantischer if/else Block im Controller.
Gut: Das Routing übernimmt das API Gateway (z. B. Kong, AWS API Gateway) vor der eigentlichen Applikation.
Das Gateway fängt an: Path: /v1/* -> Route to Microservice A (Legacy) und Path: /v2/* -> Route to Microservice B (Modern).
Dies erlaubt es, die Versionen komplett getrennt in verschiedenen Containern, in verschiedenen Sprachen und mit unterschiedlichen Laufzeiten zu deployen. Die V1 kann als legacy monolith in Java laufen, V2 in Go.
Consumer-Driven Contract Testing
Wenn du hunderte Konsumenten hast, woher weißt du, ob deine API-Änderung einen "Breaking Change" darstellt, den du übersehen hast? Hier greift Contract Testing (z.B. mit PACT). Anstatt dass der API-Anbieter schreibt: "Das ist mein Format", schreibt der Konsument (Client-App) einen Test: "Das ist das Format, das ich verstehe und brauche" (der Contract). Dieser Contract wird beim API-Provider bei jedem CI/CD-Lauf gegengeprüft. Ändert der Backend-Entwickler ein Feld und bricht damit den Vertrag eines bekannten Clients, schlägt der Build fehl, bevor die Änderung deployt wird. Dadurch wird Versioning manchmal sogar obsolet, da du garantierst, nie etwas kaputt zu machen.
Quick-Check
Was ist ein "Breaking Change"?
Alles, was bestehenden Code kaputt macht: Löschen eines Feldes, Umbenennen, Ändern eines Datentyps (String -> Int), Hinzufügen eines Pflicht-Parameters. Hinzufügen eines optionalen Feldes/Parameters ist meist "Non-Breaking".Warum nutzen Banken oft noch v1 nach 10 Jahren?
Weil Legacy-Code in Cobol-Systemen oder alten Terminals schwer zu ändern ist. "Never touch a running system". Versioning ist oft eine vertragliche Garantie.Semantic Versioning (SemVer) bei APIs?
Bei HTTP APIs meist nur Major Version (v1, v2). Minor/Patch (v1.2.3) sind für den Client oft irrelevant, solange sie kompatibel sind.