Warum Versionierung wichtig ist
Eine API ist ein Versprechen. Sobald Clients von ihr abhängig sind, führt eine leichtfertige Änderung dazu, dass deren Apps nicht mehr funktionieren – und defekte Clients sind für alle Beteiligten kostspielig. Versioning ist die Methode, mit der Sie Verbesserungen ausliefern und gleichzeitig den Clients einen stabilen Vertrag sowie einen klaren Migrationspfad bieten.
Das Ziel ist nicht, Änderungen zu vermeiden. Es geht darum, Änderungen vorhersehbar zu machen: Wissen, welche Änderungen sicher sind, Versionen konsistent bereitstellen und alte Versionen nach einem kommunizierten Zeitplan ausphasen, anstatt die Nutzer zu überraschen.
Breaking Changes vs. additive Changes
Der Großteil des Ärgers bei der Versionierung entsteht dadurch, dass Änderungen nicht richtig klassifiziert werden. Beginnen Sie mit einer klaren Regel.
Normalerweise sicher (additive):
- Hinzufügen eines neuen optionalen Feldes zu einer Response.
- Hinzufügen eines neuen Endpoints.
- Hinzufügen eines neuen optionalen Request-Parameters.
- Hinzufügen eines neuen Enum-Werts, sofern Clients unbekannte Werte tolerieren.
Breaking (erfordert eine neue Version):
- Entfernen oder Umbenennen eines Feldes.
- Ändern des Typs oder Formats eines Feldes.
- Umwandlung eines optionalen Parameters in einen Pflichtparameter.
- Änderung der Bedeutung oder des Standardverhaltens bestehender Funktionen.
- Änderung von Status-Codes oder Error-Shapes, auf die sich Clients verlassen.
Clients so zu konzipieren, dass sie unbekannte Felder ignorieren, ist der effektivste Weg, um additive Changes sicher zu gestalten. Dokumentieren Sie diese Regel, damit niemand raten muss.
Versionierungsstrategien
Es gibt vier gängige Möglichkeiten, wie Clients eine Version auswählen können.
URI-Versionierung — die Version ist Teil des Pfads.
GET /v1/posts
GET /v2/posts
Sie ist sichtbar, einfach zu routen, leicht zu cachen und unkompliziert im Browser zu testen. Dies ist die häufigste Wahl für öffentliche APIs, auch wenn Puristen argumentieren, dass sich die URL nicht ändern sollte.
Header-Versionierung — ein benutzerdefinierter Header wählt die Version aus.
GET /posts
X-API-Version: 2
Die URLs bleiben stabil, was für das Caching nach Ressourcen vorteilhaft ist, aber die Version ist in Logs, Links und Browser-Tests unsichtbar.
Media-type-Versionierung — die Inhaltsverhandlung (Content Negotiation) wählt die Version aus.
GET /posts
Accept: application/vnd.example.v2+json
Dies ist der am stärksten an REST ausgerichtete Ansatz und lässt sich gut mit Content Negotiation kombinieren, ist jedoch am schwierigsten zu entdecken und zu debuggen.
Query-Parameter — ?version=2. Einfach, aber leicht zu vergessen und ungünstig für das Caching.
Egal, für welche Variante Sie sich entscheiden: Wenden Sie diese konsistent an und dokumentieren Sie sie. Das Mischen von Strategien ist schlimmer, als eine weniger modische Methode zu wählen.
Deprecation und Sunset
Das Entfernen einer Version sollte ein Prozess sein, kein einmaliges Ereignis.
Deprecation: true
Sunset: Wed, 31 Dec 2026 23:59:59 GMT
Link: </v2/posts>; rel="successor-version"
- Deprecation kündigt an, dass eine Version oder ein Endpoint entfernt wird.
- Sunset gibt das genaue Datum an, an dem die Funktion nicht mehr zur Verfügung steht.
- Link verweist auf den Ersatz.
Kombinieren Sie die Header mit einem Migrationsleitfaden, Einträgen im Changelog und einer direkten Kommunikation an Intensivnutzer. Überwachen Sie anschließend die Nutzung: Wenn kurz vor dem Sunset-Datum immer noch ein signifikanter Anteil des Traffics die alte Version nutzt, verlängern Sie die Frist, anstatt diese Clients funktionsunfähig zu machen.
Versionen parallel betreiben
Die Unterstützung von zwei Versionen bedeutet, dass der Code beide bedienen muss. Gängige Ansätze sind:
- Versionierte Handler, die auf gemeinsame Services verweisen, sodass die Business-Logik an einem zentralen Ort verbleibt.
- Adapter, die zwischen der alten und der neuen Repräsentation übersetzen.
- Feature Flags für den schrittweisen Rollout neuen Verhaltens.
- Separate Specs pro Version, die zusammen mit der API generiert und veröffentlicht werden.
Halten Sie die Unterschiede zwischen den Versionen gering. Große Forks in der Logik sind schwer zu warten und neigen dazu, mit der Zeit zu stark voneinander abzuweichen.
Änderungen kommunizieren
Versionierung funktioniert nur, wenn die Clients wissen, was passiert.
- Veröffentlichen Sie ein Changelog und kennzeichnen Sie Breaking Changes deutlich.
- Pflegen Sie pro Version eine aktuelle OpenAPI spec.
- Versenden Sie Deprecation Notices in den Headern und, sofern möglich, per E-Mail.
- Stellen Sie einen Migrationsleitfaden mit Vorher-Nachher-Beispielen bereit.
- Gewähren Sie ein Support-Zeitfenster, das auf die Release-Zyklen Ihrer Nutzer abgestimmt ist.
Best Practices
- Klassifizieren Sie jede Änderung vor dem Release als additive oder breaking change.
- Bevorzugen Sie additive Änderungen; erhöhen Sie die Version nur, wenn es unbedingt notwendig ist.
- Entscheiden Sie sich für eine Versionierungsstrategie und wenden Sie diese konsistent überall an.
- Entfernen Sie niemals ein Feld oder einen Endpoint ohne eine entsprechende Deprecation-Phase.
- Kündigen Sie die Deprecation über Header und ein Sunset-Datum an.
- Überwachen Sie den Traffic pro Version, bevor Sie eine Version einstellen.
- Kapseln Sie gemeinsam genutzte Logik hinter versionsspezifischen Adaptern.
Häufige Fehler
- Clients stillschweigend durch die Änderung der Response-Struktur zu beeinträchtigen.
- Jede kleinste Änderung zu versionieren und so einen enormen Wartungsaufwand zu schaffen.
- Unterschiedliche Versionierungsstrategien innerhalb derselben API zu vermischen.
- Eine Version ohne Vorwarnung oder Migrationspfad zu entfernen.
- Alte Versionen ohne konkreten Plan ewig weiterlaufen zu lassen.
- Zu vergessen, die Dokumentation und Spezifikationen für jede Version zu aktualisieren.
Wie geht es weiter?
Versionierung ist entscheidend dafür, wie eine API den Kontakt mit echten Clients übersteht. Setzen Sie auf ein sauberes REST-Design, beschreiben Sie jede Version mit OpenAPI und nutzen Sie HTTP-Header, um die Veralterung (Deprecation) zu kommunizieren. Erstellen Sie anschließend eine kurze Richtlinie für Ihre eigene API: Legen Sie fest, was als Breaking Change gilt und wie lange einzelne Versionen unterstützt werden.