1 Punkte von GN⁺ 4 시간 전 | 1 Kommentare | Auf WhatsApp teilen
  • Wenn eine öffentliche Web-API einen Namen wie Product API zusammen mit einem Pfad wie /api/v1 verwendet, können die semantische Version der API selbst und ihre Struktur auseinanderlaufen
  • Wenn /v1/ und major.minor.patch parallel verwendet werden, vermischen sich Routen und API-Vertrag, und die erste Zahl der semantischen Version wird in der URL fest verankert
  • Bei inkompatiblen Änderungen werden ein neuer Pfad und Reverse-Proxy-Routen nötig, wodurch Vertragsinformationen auf URL und Versionsnummer verteilt werden können
  • Wenn gleichzeitig nachfolgende APIs entwickelt werden, ist die bestehende API faktisch an v1 gebunden, und bei späteren Breaking Changes wird die Bedeutung von Name und Pfad uneindeutig
  • Es geht um die Frage, welche bei der Versionierung öffentlicher Web-APIs immer wieder störenden Ansätze es gibt und nach welchen besseren Designprinzipien man stattdessen suchen sollte

1 Kommentare

 
GN⁺ 4 시간 전
Lobste.rs-Meinungen
  • /v1/ in der URL zu haben, ist tatsächlich einer der großen Vorteile. Denn bis man einen Endpunkt abschaltet, erzwingt es gegenüber den Nutzern, dass die API nicht kaputtgemacht wird

  • Andere Texte desselben Autors wie Evolving HTTP APIs geben nützliche Ratschläge

  • Grundsätzlich versieht man jede Route mit /v1/, /v2/ usw., um Breaking Changes zu kennzeichnen. Wenn es sich nicht um einen Standard handelt, der auf mehreren Hosts funktionieren soll, sondern um eine öffentlich betriebene API, gibt es wenig Grund für vollständiges Semantic Versioning
    Semantic Versioning existiert ja vor allem, damit andere Entwickler Abhängigkeiten mit gutem Gewissen aktualisieren können, ohne jedes Mal 20 Minuten Changelog zu lesen. Bei einer produktiven API können sich die Leute aber nicht aussuchen, wann sie eine neue Minor- oder Patch-Version übernehmen
    Als Breaking Change würde ich alles ansehen, was ein dokumentiertes Verhalten verändert oder bestehende Clients kaputtmacht, die sich auf dokumentiertes Verhalten verlassen. Manche zählen auch Änderungen an undokumentiertem Verhalten als Breaking Change, aber das ist mit vielen Risiken verbunden

  • Google macht es so: AIP-185: API Versioning, AIP-180: Bacwards compatibility
    Diese Designdokumente wirken auf mich ziemlich stark auf Googles Arbeitsweise zugeschnitten, aber ich habe sie beim Entwerfen von APIs als Referenz genutzt, und einige Ideen daraus waren sehr hilfreich

  • Generell sollte jede API meiner Meinung nach versuchen, Breaking Changes so weit wie möglich zu vermeiden. Wenn man zum Beispiel einen Attributnamen ändern will, ist es meist besser, den neuen Namen zusätzlich einzuführen, statt das bisherige Attribut zu entfernen
    Allerdings ist auch der Ansatz von the people at Buttondown do it sauber. Dort werden Migrationen zwischen API-Versionen definiert, sodass Verbraucher ihre API-Version per Header festschreiben können, während der Anbieter Änderungen weiter vorantreibt

    • Bei Ausgabeattributen hat das Duplizieren von Attributen ziemlich gut funktioniert. Bei Eingaben muss man aber Fälle behandeln, in denen der Client beide Attribute mit unterschiedlichen Werten sendet
      Man denkt sofort an „der neue Name hat immer Vorrang“, aber das kann scheitern, wenn ein Client einen Read-Modify-Write-Ablauf ausführt und eine bearbeitete Version eines serverseitig erzeugten Objekts zurückschickt. Der Client könnte nämlich nur das alte Attribut aktualisieren und das neue unverändert wieder mitsenden
    • Wie vom API-Anbieter beschrieben, klingt es gut, Migrationen zwischen API-Versionen bereitzustellen, aber using an HTTP request header for versioning can cause problems
    • Der verlinkte Beitrag erklärt sehr gut, wie man mit der Datenform umgeht. Das ist aber nur ein Teil davon, und ich frage mich, wie man vorgeht, wenn sich das Verhalten selbst ändert
      Solche Transformationen ließen sich vermutlich auch auf Verhaltenszuordnungen anwenden, aber sofern ich nichts übersehen habe, wurde dieser Punkt dort nicht behandelt
  • Idealerweise nimmt man die Version in den Pfad auf, und neue Versionen sollten additiv sein. Dann kann eine ältere API-Version Anfragen nach den nötigen Ein-/Ausgabe-Transformationen an eine neuere API-Version weiterleiten
    Wenn nach ein paar Jahren niemand mehr irgendeine alte Version verwendet, kann man sie entfernen, und der /v1/-Pfad liefert dann einen Fehler

  • Ich habe früher ein wenig über API-Versionierung via Content Negotiation über den Accept-Header gelesen. Falls das jemand in der Praxis gemacht hat, würde mich die Erfahrung interessieren
    Nach meiner Erfahrung waren versionsbezogene Ansätze pro Ressource oder global am intuitivsten. Für die Ausphasung erscheint mir die Kombination aus dem Deprecation-HTTP-Response-Header (RFC 9745) und später Antworten wie 410 Gone für alte Endpunkte als ein vernünftiger Weg, Clients zum Umstieg auf neue Versionen zu bewegen
    Außerdem würde mich wirklich interessieren, ob jemand schon einmal eine evolvierbare API gebaut hat. Also eine, die Anfragen an alte Versionen intern in Anfragen an eine neue API-Version übersetzt und die alte Version dann entfernt, sobald die Clients migriert sind oder genug Zeit vergangen ist