876 Stimmen

Bewährte Verfahren für die API-Versionierung?

Gibt es bekannte Anleitungen oder bewährte Verfahren für die Versionierung von REST-APIs für Webdienste?

Ich habe festgestellt, dass AWS führt die Versionierung über die URL des Endpunkts durch . Ist dies der einzige Weg oder gibt es noch andere Möglichkeiten, das gleiche Ziel zu erreichen? Wenn es mehrere Möglichkeiten gibt, was sind die Vorzüge der einzelnen Möglichkeiten?

682voto

Shonzilla Punkte 7894

Das ist eine gute und eine schwierige Frage. Das Thema der URI-Design ist zur gleichen Zeit der wichtigste Teil einer REST-API und daher ein potenzielles langfristiges Engagement gegenüber den Nutzern dieser API .

Da die Entwicklung einer Anwendung und, in geringerem Maße, ihrer API eine Tatsache des Lebens ist und sogar mit der Entwicklung eines scheinbar komplexen Produkts wie einer Programmiersprache vergleichbar ist, ist die URI-Entwurf weniger haben sollte natürliche Beschränkungen und es im Laufe der Zeit bewahrt werden sollten . Je länger die Lebensdauer der Anwendung und der API ist, desto größer ist die Verpflichtung gegenüber den Nutzern der Anwendung und der API.

Andererseits ist es auch eine Tatsache, dass es schwierig ist, alle Ressourcen und ihre Aspekte, die über die API verbraucht werden, vorherzusehen. Glücklicherweise ist es nicht notwendig, die gesamte API zu entwerfen, die bis zum Ende der Laufzeit verwendet werden soll. Apokalypse . Es reicht aus, alle Ressourcenendpunkte und das Adressierungsschema jeder Ressource und Ressourceninstanz korrekt zu definieren.

Im Laufe der Zeit müssen Sie möglicherweise neue Ressourcen und neue Attribute zu jeder einzelnen Ressource hinzufügen, aber die Methode, mit der API-Benutzer auf eine bestimmte Ressource zugreifen, sollte sich nicht mehr ändern, sobald ein Ressourcenadressierungsschema öffentlich und damit endgültig wird.

Diese Methode gilt für die Semantik von HTTP-Verben (z. B. sollte PUT immer aktualisieren/ersetzen) und HTTP-Statuscodes, die in früheren API-Versionen unterstützt werden (sie sollten weiterhin funktionieren, damit API-Clients, die ohne menschliches Eingreifen funktioniert haben, auch weiterhin so arbeiten können).

Da die Einbettung der API-Version in den URI außerdem das Konzept der Hypermedia als Motor des Anwendungsstatus (in Roy T. Fieldings Dissertation) durch eine Ressourcenadresse/URI, die sich im Laufe der Zeit ändern würde, würde ich zu dem Schluss kommen, dass API-Versionen sollten nicht lange in Ressourcen-URIs gespeichert werden was bedeutet, dass Ressourcen-URIs, auf die sich API-Nutzer verlassen können, sollten Permalinks sein .

Ja, sicher, es ist möglich, die API-Version in den Basis-URI einzubetten sondern nur für sinnvolle und eingeschränkte Zwecke wie das Debuggen eines API-Clients die mit der neuen API-Version funktioniert. Solche versionierten APIs sollten zeitlich begrenzt und nur für begrenzte Gruppen von API-Benutzern (z. B. während geschlossener Betas) verfügbar sein. Andernfalls verpflichten Sie sich, wo Sie es nicht sollten.

Einige Gedanken zur Wartung von API-Versionen, die ein Verfallsdatum haben. Alle Programmierplattformen/Sprachen, die üblicherweise zur Implementierung von Webdiensten verwendet werden (Java, .NET, PHP, Perl, Rails usw.), ermöglichen die einfache Bindung von Webdienst-Endpunkten an einen Basis-URI. Auf diese Weise ist es einfach sammeln und aufbewahren eine Sammlung von Dateien/Klassen/Methoden getrennt für verschiedene API-Versionen .

Aus der Sicht der API-Benutzer ist es auch einfacher, mit einer bestimmten API-Version zu arbeiten und sich an sie zu binden, wenn sie so offensichtlich ist, aber nur für eine begrenzte Zeit, d. h. während der Entwicklung.

Aus der Sicht des API-Wartungsbeauftragten ist es einfacher, verschiedene API-Versionen parallel zu warten, indem er Versionskontrollsysteme verwendet, die hauptsächlich mit Dateien als kleinster Einheit der (Quellcode-)Versionierung arbeiten.

Bei API-Versionen, die in der URI klar ersichtlich sind, gibt es jedoch einen Vorbehalt: Man könnte diesen Ansatz auch ablehnen, da API-Verlauf wird im URI-Design sichtbar/übergeordnet und ist daher anfällig für Veränderungen im Laufe der Zeit was gegen die Richtlinien von REST verstößt. Ich stimme zu!

Der Weg, diesen vernünftigen Einwand zu umgehen, ist die Implementierung der neuesten API-Version unter dem versionslosen API-Basis-URI. In diesem Fall können API-Client-Entwickler wählen, ob sie:

  • gegen die neueste Version entwickeln (und sich verpflichten, die Anwendung zu pflegen, um sie vor eventuellen API-Änderungen zu schützen, die ihre schlecht gestalteter API-Client ).

  • sich an eine bestimmte Version der API zu binden (was offensichtlich wird), aber nur für eine begrenzte Zeit

Wenn z. B. API v3.0 die neueste API-Version ist, sollten die beiden folgenden Aliase sein (d. h. sich bei allen API-Anfragen identisch verhalten):

http://shonzilla/api/customers/1234 http://shonzilla/api**/v3.0**/customers/1234 http://shonzilla/api**/v3**/customers/1234

Darüber hinaus können API-Clients, die weiterhin versuchen, auf die alt API sollte darüber informiert werden, dass die neueste, frühere API-Version verwendet wird, wenn die von ihnen verwendete API-Version veraltet ist oder nicht mehr unterstützt wird . Der Zugriff auf eine der veralteten URIs wie diese:

http://shonzilla/api**/v2.2**/customers/1234
http://shonzilla/api**/v2.0**/customers/1234
http://shonzilla/api**/v2**/customers/1234
http://shonzilla/api**/v1.1**/customers/1234
http://shonzilla/api**/v1**/customers/1234

sollte eine der 30x HTTP-Statuscodes, die eine Umleitung anzeigen die in Verbindung verwendet werden mit Location HTTP-Header, der auf die entsprechende Version der Ressourcen-URI umleitet, die weiterhin diese ist:

http://shonzilla/api/customers/1234

Es gibt mindestens zwei HTTP-Statuscodes für die Umleitung, die für API-Versionierungsszenarien geeignet sind:

  • 301 Dauerhaft verschoben die anzeigt, dass die Ressource mit einem angeforderten URI dauerhaft auf einen anderen URI verschoben wird (der ein Ressourceninstanz-Permalink sein sollte, der keine API-Versionsinformationen enthält). Dieser Statuscode kann verwendet werden, um eine veraltete/nicht unterstützte API-Version anzuzeigen und den API-Client zu informieren, dass eine versionierter Ressourcen-URI wurde durch einen Ressourcen-Permalink ersetzt .

  • 302 gefunden der angibt, dass sich die angeforderte Ressource vorübergehend an einem anderen Ort befindet, während der angeforderte URI noch unterstützt werden kann. Dieser Statuscode kann nützlich sein, wenn versionslose URIs vorübergehend nicht verfügbar sind und eine Anfrage unter Verwendung der Umleitungsadresse (z. B. mit Verweis auf den URI mit eingebetteter APi-Version) wiederholt werden sollte und wir den Clients mitteilen wollen, dass sie diese weiterhin verwenden sollen (d. h. die Permalinks).

  • andere Szenarien finden Sie unter Umleitung 3xx Kapitel der HTTP 1.1 Spezifikation

142 Stimmen

Die Verwendung einer Versionsnummer in der URL sollte nicht als schlechte Praxis angesehen werden, wenn sich die zugrunde liegende Implementierung ändert. "Wenn sich die Schnittstelle zu einem Dienst in einer nicht rückwärtskompatiblen Weise ändert, wurde in Wirklichkeit ein völlig neuer Dienst geschaffen...Aus der Sicht des Kunden ist ein Dienst nicht mehr als eine Schnittstelle und einige nicht-funktionale Eigenschaften...Wenn sich die Schnittstelle zu einem Dienst in einer nicht rückwärtskompatiblen Weise ändert, stellt er nicht länger eine Instanz des ursprünglichen Dienstes dar, sondern ist vielmehr ein völlig neuer Dienst." ibm.com/developerworks/webservices/library/ws-version

7 Stimmen

Können Sie sich vorstellen, eine Kopfzeile mit der Versionsnummer hinzuzufügen, damit sie von Kunden oder Entwicklern überprüft werden kann?

2 Stimmen

Theoretisch ist das eine gute Idee, es sei denn, die Anfragen laufen entweder über Proxy-Server oder der API-Server befindet sich hinter einem CDN (wie Akamai), da diese einige HTTP-Header herausfiltern könnten. Die Verwendung eines Standard-Headers ("Schmuggeln" der API-Version, z. B. Server: SomeAPI/2.1) anstelle eines benutzerdefinierten Headers (z. B. X-API-Version: 2.1) ist eine gute Idee. In jedem Fall müssen Sie dies mit Ihrem Provider abklären und eine Art langfristige Verpflichtung eingehen, bevor Sie Ihre Kunden zur Verwendung des Headers zwingen.

273voto

jeremyh Punkte 5102

Die URL sollte NICHT die Versionen enthalten. Die Version hat nichts mit der "Idee" der von Ihnen angeforderten Ressource zu tun. Sie sollten versuchen, die URL als einen Pfad zu dem gewünschten Konzept zu betrachten - nicht als die Art und Weise, wie Sie das Objekt zurückerhalten möchten. Die Version gibt die Darstellung des Objekts vor, nicht das Konzept des Objekts. Wie bereits gesagt wurde, sollten Sie das Format (einschließlich der Version) in der Kopfzeile der Anfrage angeben.

Wenn Sie sich die vollständige HTTP-Anfrage für die URLs, die Versionen haben, ansehen, sieht es wie folgt aus:

(BAD WAY TO DO IT):

http://company.com/api/v3.0/customer/123
====>
GET v3.0/customer/123 HTTP/1.1
Accept: application/xml

<====
HTTP/1.1 200 OK
Content-Type: application/xml
<customer version="3.0">
  <name>Neil Armstrong</name>
</customer>

Der Header enthält die Zeile, die die gewünschte Darstellung enthält ("Accept: application/xml"). Dort sollte auch die Version stehen. Alle scheinen die Tatsache zu übersehen, dass man das Gleiche in verschiedenen Formaten haben möchte und dass der Kunde in der Lage sein sollte, das zu verlangen, was er möchte. Im obigen Beispiel fragt der Kunde nach ANY XML-Darstellung der Ressource - nicht wirklich die wahre Darstellung dessen, was sie will. Theoretisch könnte der Server etwas zurückgeben, das nichts mit der Anfrage zu tun hat, solange es sich um XML handelt, und es müsste geparst werden, um zu erkennen, dass es falsch ist.

Ein besserer Weg ist:

(GOOD WAY TO DO IT)

http://company.com/api/customer/123
===>
GET /customer/123 HTTP/1.1
Accept: application/vnd.company.myapp.customer-v3+xml

<===
HTTP/1.1 200 OK
Content-Type: application/vnd.company.myapp-v3+xml
<customer>
  <name>Neil Armstrong</name>
</customer>

Angenommen, die Kunden finden XML zu langatmig und wollen stattdessen JSON. In den anderen Beispielen müssten Sie eine neue URL für den gleichen Kunden haben, so dass Sie am Ende mit:

(BAD)
http://company.com/api/JSONv3.0/customers/123
  or
http://company.com/api/v3.0/customers/123?format="JSON"

(oder etwas Ähnliches). In Wirklichkeit enthält jede HTTP-Anfrage das gesuchte Format:

(GOOD WAY TO DO IT)
===>
GET /customer/123 HTTP/1.1
Accept: application/vnd.company.myapp.customer-v3+json

<===
HTTP/1.1 200 OK
Content-Type: application/vnd.company.myapp-v3+json

{"customer":
  {"name":"Neil Armstrong"}
}

Mit dieser Methode hat man viel mehr Gestaltungsfreiheit und hält sich eigentlich an die ursprüngliche Idee von REST. Sie können Versionen ändern, ohne die Clients zu beeinträchtigen, oder die Clients schrittweise ändern, wenn die APIs geändert werden. Wenn Sie beschließen, eine Darstellung nicht mehr zu unterstützen, können Sie auf die Anfragen mit einem HTTP-Statuscode oder benutzerdefinierten Codes antworten. Der Client kann auch überprüfen, ob die Antwort im richtigen Format vorliegt, und das XML validieren.

Es gibt noch viele weitere Vorteile, von denen ich einige hier in meinem Blog erörtere: http://thereisnorightway.blogspot.com/2011/02/versioning-and-types-in-resthttp-api.html

Ein letztes Beispiel, um zu zeigen, dass die Angabe der Version in der URL schlecht ist. Angenommen, Sie wollen eine Information innerhalb des Objekts und haben Ihre verschiedenen Objekte versioniert (Kunden sind v3.0, Aufträge sind v2.0 und das shipto-Objekt ist v4.2). Hier ist die unangenehme URL, die Sie im Client angeben müssen:

(Another reason why version in the URL sucks)
http://company.com/api/v3.0/customer/123/v2.0/orders/4321/

10 Stimmen

Die Handhabung unabhängiger Datenvertragsversionen und Servicevertragsversionen in der Kopfzeile "Akzeptieren" scheint ebenso chaotisch zu sein wie in der URL. Gibt es andere Möglichkeiten? Wenn ich mehrere Endpunkte habe (soap, rest), sollte dies auch in den Accept-Headern angegeben werden und der Routing-Dienst am Server-Ende über die Richtung zum richtigen Endpunkt entscheiden, oder ist es akzeptabel, den Endpunkt in der URL zu codieren?

0 Stimmen

unternehmen.com/api/v3.0/kunden/123/v2.0/bestellungen/4321 hat Ihre Erklärung deutlich gemacht. Ein gutes Beispiel!

1 Stimmen

Ich denke, das hängt vom Anwendungsfall ab. Bei der Arbeit an unternehmensinternen Systemen ist die Versionierung des Webservice erforderlich, damit andere interne Systeme (Clients des Webservice) Zeit haben, auf die neueste Version zu aktualisieren. So kann die alte Version für einen bestimmten Zeitraum (z. B. nur 1 Monat) unterstützt und dann abgeschaltet werden. In diesem Fall scheint es für mich kein Problem zu sein, die Version in der URL zu haben.

98voto

Yoav Shapira Punkte 1161

Wir fanden es praktisch und nützlich, die Version in der URL anzugeben. So lässt sich auf einen Blick erkennen, welche Version Sie verwenden. Wir verwenden den Alias /foo für /foo/ (neueste Versionen) aus Gründen der Benutzerfreundlichkeit, kürzerer / sauberer URLs usw., wie die akzeptierte Antwort nahelegt.

Die Aufrechterhaltung der Abwärtskompatibilität für immer ist oft kostenintensiv und/oder sehr schwierig. Wir ziehen es vor, die Veraltung im Voraus anzukündigen, Weiterleitungen wie hier vorgeschlagen, Dokumente und andere Mechanismen.

5 Stimmen

Die akzeptierte Antwort kann die richtige und reinste sein. Für den Entwickler und alltäglichen Nutzer von APIs ist dies jedoch sicherlich die einfachste Lösung. Es ist der pragmatischste Ansatz. Wie von anderen angedeutet, verwenden auch Google und Amazon diesen Ansatz.

46voto

Kevsy Punkte 605

Ich stimme zu, dass die Versionierung der Ressourcendarstellung besser dem REST-Ansatz folgt... aber ein großes Problem mit benutzerdefinierten MIME-Typen (oder MIME-Typen, die einen Versionsparameter anhängen) ist die schlechte Unterstützung zum Schreiben in Accept- und Content-Type-Header in HTML und JavaScript.

Zum Beispiel ist es IMO nicht möglich, in HTML5-Formularen mit den folgenden Kopfzeilen zu posten, um eine Ressource zu erstellen:

Accept: application/vnd.company.myapp-v3+json
Content-Type: application/vnd.company.myapp-v3+json 

Das liegt daran, dass die HTML5 enctype Attribut ist eine Aufzählung, weshalb alles andere als die üblichen application/x-www-formurlencoded , multipart/form-data y text/plain sind ungültig.

...und ich bin mir auch nicht sicher, ob es von allen Browsern in HTML4 unterstützt wird (das ein laxeres encytpe-Attribut hat, aber es wäre eine Frage der Browser-Implementierung, ob der MIME-Typ weitergeleitet wird)

Aus diesem Grund bin ich der Meinung, dass die Versionierung über den URI am besten geeignet ist, aber ich akzeptiere, dass dies nicht der "richtige" Weg ist.

14 Stimmen

Geht man von der Route aus, bei der die Versionierung in den Kopfzeilen definiert wurde, könnte man sagen, dass HTML-Formulare, die die native Formularübermittlung verwenden, immer die neueste Version der API verwenden würden, da sie die spezifische Version, an die sie sich halten wollen, nicht übergeben würden. XHR-Anfragen erlauben es jedoch, die Akzeptanz zu ändern und die Content-Type-Header zu lesen. Das einzige Problem sind also wirklich die Basisformulare.

0 Stimmen

Ich bin nicht sicher, ob ich zustimme, dass URI am besten geeignet ist, aber die Tatsache, dass Content-Type nicht mit Formularen funktioniert, ist in der Tat sehr wichtig.

2 Stimmen

@Kyle, sah ich einen Blog irgendwo sagte, dass, wenn Sie nicht eine bestimmte Version in der Anfrage-Header, ist es am besten, mit der ersten API-Version nicht die neueste für die beste kompatiblen zurück.

21voto

Sean O'Dell Punkte 378

Geben Sie Ihre Version in den URI ein. Eine Version einer API unterstützt nicht immer die Typen einer anderen, so dass das Argument, Ressourcen würden lediglich von einer Version in eine andere migriert, schlichtweg falsch ist. Es ist nicht dasselbe wie der Formatwechsel von XML zu JSON. Die Typen existieren vielleicht gar nicht, oder sie haben sich semantisch verändert.

Die Versionen sind Teil der Ressourcenadresse. Sie leiten von einer API zu einer anderen weiter. Es ist nicht RESTful, die Adressierung im Header zu verstecken.

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X