Diskussionen über API-Versionierung beginnen meist am falschen Ende, nämlich bei der Frage, wo die Versionsnummer steht. Das ist die folgenloseste Entscheidung des ganzen Themas. Entscheidend ist, welche Änderungen überhaupt eine neue Version verlangen, und die meisten Teams irren sich dabei in Richtung Sorglosigkeit: Sie liefern etwas aus, das sie für rein additiv halten, und ein Client geht kaputt.

Das brauchbare Denkmodell lautet: Ihre API ist ein Versprechen darüber, worauf ein Aufrufer sich verlassen darf. Eine Änderung ist brechend, wenn sie etwas ungültig macht, worauf ein vernünftiger Aufrufer sich verlassen hat, und Aufrufer verlassen sich auf mehr, als Ihre Dokumentation ihnen ausdrücklich zugesteht.

Die Änderung, die alle erwischt: ein Feld zu einer Antwort hinzufügen. Sie ist additiv, sie kann einen sauber geschriebenen Client nicht brechen, und sie bricht echte Clients regelmäßig, weil manche davon Antworten streng validieren und unbekannte Felder ablehnen. Ob das Ihre Schuld ist oder deren, spielt keine Rolle mehr, sobald die Integration steht und das Telefon klingelt.


Was wirklich als brechend zählt

Eindeutig brechend: ein Feld entfernen oder umbenennen, den Typ eines Feldes ändern, einen Pflichtparameter zur Anfrage hinzufügen, die Validierung verschärfen, die Bedeutung eines bestehenden Wertes ändern oder einen Statuscode ändern, auf den ein Aufrufer verzweigt.

In der Praxis brechend, obwohl es sicher aussieht: ein Feld zu einer Antwort hinzufügen, wenn Clients streng validieren. Die Reihenfolge eines Arrays ändern, die nie zugesagt war, die Aufrufer aber angenommen haben. Eine Fehlermeldung ändern, auf deren Text jemand als Zeichenkette abgleicht. Eine synchrone Operation asynchron machen.

Wirklich sicher: einen neuen optionalen Anfrageparameter hinzufügen, einen neuen Endpunkt hinzufügen, die Validierung lockern, und einen neuen Wert zu einer Aufzählung hinzufügen, aber nur, wenn Clients von Anfang an gesagt wurde, mit unbekannten Werten zu rechnen, und Sie überprüfen können, dass sie damit umgehen.

Das Muster dahinter: Sicherheit hängt davon ab, was Aufrufer tatsächlich tun, nicht davon, was die Spezifikation erlaubt. Wenn Sie jeden Client kontrollieren, können Sie es nachprüfen. Wenn nicht, gehen Sie davon aus, dass sich jemand auf genau das verlässt, was Sie für nebensächlich hielten, denn genau so ist es.

Strategien zur API-Versionierung und was sie kosten

Version in der URL. Der verbreitetste Ansatz, und sein Vorzug ist die Offensichtlichkeit: /v1/orders und /v2/orders sind sichtbar verschiedene Ressourcen. Der Preis dafür ist, dass er Versionssprünge der ganzen API begünstigt, sodass eine Änderung an einem einzigen Endpunkt alles andere mitzieht und Clients auf einen Schlag migrieren müssen.

Version in einem Header. Hält URLs stabil und erlaubt feinere Granularität, um den Preis der Unsichtbarkeit. Niemand sieht die Version im Browser oder in einer Logzeile, ohne gezielt danach zu suchen, und ein Aufrufer, der den Header weglässt, bekommt Ihren Standardwert, was eine Entscheidung ist, die Sie bewusst treffen müssen.

Datumsbasierte Versionierung. Ein Aufrufer legt sich auf ein Datum fest und erhält die API so, wie sie sich damals verhalten hat. Stripe dokumentiert diesen Ansatz, bei dem jedes Konto eine Standardversion hat und einzelne Anfragen sie überschreiben können. Er ergibt die kleinstmöglichen Migrationsschritte und schiebt die Last der Kompatibilität in Ihre eigene Codebasis, die nun Transformationen zwischen den Versionen pflegt.

Keine Versionierung, nur additive Änderung. Tragfähig und unterschätzt, wenn Sie sich ernsthaft darauf festlegen können, nie etwas zu entfernen. Der Preis sind Felder, die Sie nicht mehr löschen können, und Verhalten, das Sie nicht mehr korrigieren können, also eine langsame Steuer statt einer akuten Rechnung.

Es gibt keine richtige Antwort, nur einen Tausch zwischen Ihrer Migrationslast und der Ihrer Kunden. Datumsbasierte Versionierung ist die freundlichste für Aufrufer und die teuerste im Betrieb. URL-Versionierung ist das Gegenteil.

Brechende Änderungen überlebbar machen

Erst erweitern, dann zusammenziehen. Fügen Sie das neue Feld neben dem alten hinzu. Befüllen Sie beide. Geben Sie Clients Zeit für den Wechsel. Entfernen Sie das alte in einer späteren Version. Das verwandelt eine brechende Änderung in zwei sichere und ist den zusätzlichen Schritt fast immer wert.

Messen Sie, wer was benutzt. Sie können eine Version nicht sicher abschalten, ohne zu wissen, wer noch darauf sitzt. Protokollieren Sie bei jeder Anfrage die Version und die Identität des Clients, damit aus der Abkündigung ein Gespräch auf Basis von Belegen wird statt einer Ansage ins Dunkle.

Kündigen Sie mit einem Mechanismus an, nicht nur per E-Mail. Die Antwort-Header Deprecation und Sunset erlauben es einem Client, das Abschaltdatum programmatisch zu entdecken, und das wird eher bemerkt als eine Nachricht an eine Adresse, die niemand mehr liest.

Setzen Sie ein realistisches Zeitfenster. Integrationen werden von Menschen mit anderen Prioritäten gepflegt, und eine Frist, die kürzer ist als deren Releasezyklus, wird schlicht verpasst. Sechs Monate sind für eine öffentliche API üblich; weniger ist vertretbar bei einer kleinen Zahl bekannter Partner, mit denen Sie gesprochen haben.

Eine alte Version abschalten

Die Messung von oben ist das, was diesen Schritt überhaupt möglich macht. Kündigen Sie das Datum an, beobachten Sie, wie der Verkehr zurückgeht, und sprechen Sie die Aufrufer, die nicht gewechselt haben, namentlich an.

Rechnen Sie mit einem langen Schwanz. Es wird Integrationen geben, an deren Besitz sich beim Kunden niemand mehr erinnert, und entdeckt werden sie in dem Moment, in dem Sie die Version abschalten. Brownouts helfen hier: Deaktivieren Sie die alte Version vor dem endgültigen Termin kurz zu angekündigten Zeiten, damit der Ausfall dann passiert, wenn jemand ihn erwartet, und nicht mitten in einer stressigen Phase.

Die ehrliche Position lautet: Manche Aufrufer wechseln erst, wenn die alte Version aufhört zu funktionieren. Planen Sie damit, statt sich davon überraschen zu lassen, und sorgen Sie dafür, dass der Fehlerfall eine klare Meldung ist, die erklärt, was passiert ist, und kein Timeout.

Die Version, die Sie nicht brauchen

Die meisten internen APIs brauchen überhaupt keine Versionierung, weil Sie jeden Aufrufer kontrollieren und beide Seiten gemeinsam ändern können. Einer Schnittstelle zwischen zwei Ihrer eigenen Dienste eine Versionsaushandlung zu verpassen, ist Maschinerie, die etwas kostet und vor nichts schützt.

Notwendig wird sie an dem Punkt, an dem Sie nicht mehr jeden Konsumenten gleichzeitig ausrollen können, sei es weil er einem anderen Team, einem anderen Releasezyklus oder einer anderen Firma gehört. Das ist der eigentliche Auslöser, und er hat nichts damit zu tun, wie öffentlich die API ist. Die Entwurfsüberlegungen aus unserem Leitfaden für Serverless-APIs gelten am Edge auf genau dieselbe Weise.

Mecanik entwirft und pflegt APIs dieser Art als Teil unserer Arbeit in der Softwareentwicklung. Das Versionsschema ist selten die interessante Entscheidung; zu wissen, welcher Ihrer Aufrufer noch auf der alten Version sitzt, ist es immer.



Häufig gestellte Fragen

Was gilt als brechende API-Änderung? Ein Feld entfernen oder umbenennen, den Typ eines Feldes ändern, einen Pflichtparameter hinzufügen, die Validierung verschärfen, die Bedeutung eines Wertes ändern oder einen Statuscode ändern, auf den Aufrufer verzweigen. In der Praxis ebenfalls brechend: ein Antwortfeld hinzufügen, wenn Clients streng validieren, die von Aufrufern angenommene Array-Reihenfolge ändern und den Text einer Fehlermeldung ändern, auf den jemand abgleicht.

Gehört die API-Version in die URL oder in einen Header? URL-Versionierung ist sichtbar und einfach, begünstigt aber Sprünge der ganzen API und zwingt Clients, alles auf einmal zu migrieren. Header-Versionierung hält URLs stabil und erlaubt feinere Granularität, ist aber in Logs und Browsern unsichtbar und verlangt einen bewussten Standardwert für Aufrufer, die den Header weglassen. Keines von beidem ist falsch; sie tauschen Ihre Migrationslast gegen die Ihrer Kunden.

Was ist datumsbasierte API-Versionierung? Ein Aufrufer legt sich auf ein Datum fest und erhält die API so, wie sie sich damals verhalten hat, wie Stripe es mit einer Standardversion je Konto macht, die einzelne Anfragen überschreiben können. Das ergibt für Clients die kleinstmöglichen Migrationsschritte und verschiebt die Last der Kompatibilität in Ihre Codebasis, die dann Transformationen zwischen den Versionen pflegt.

Wie lang sollte ein Zeitfenster für die API-Abkündigung sein? Sechs Monate sind für eine öffentliche API üblich, und weniger ist vertretbar bei einer kleinen Zahl bekannter Partner, mit denen Sie direkt gesprochen haben. Integrationen werden von Menschen mit anderen Prioritäten gepflegt, daher wird ein Fenster, das kürzer ist als deren Releasezyklus, verpasst, ganz gleich wie deutlich es angekündigt wurde.

Brauchen interne APIs eine Versionierung? Meistens nicht, weil Sie jeden Aufrufer kontrollieren und beide Seiten gemeinsam ändern können. Notwendig wird Versionierung an dem Punkt, an dem Sie nicht mehr alle Konsumenten gleichzeitig ausrollen können, sei es weil sie einem anderen Team, Releasezyklus oder Unternehmen gehören. Das ist der Auslöser, nicht die Frage, ob die API öffentlich ist.