web-dev-qa-db-fra.com

Meilleures pratiques pour la gestion des versions d'API?

Existe-t-il des procédures ou des pratiques recommandées pour les versions de service de service Web REST API?

J'ai remarqué que AWS effectue la gestion des versions à l'aide de l'URL du noeud final . Est-ce le seul moyen ou existe-t-il d'autres moyens d'atteindre le même objectif? S'il y a plusieurs moyens, quels sont les avantages de chaque moyen?

877
Swaroop C H

C'est une bonne et une question délicate. Le sujet de la conception de l'URI est en même temps la partie la plus importante d'un REST API et , donc, un engagement potentiellement à long terme envers les utilisateurs de cette API .

Depuis l’évolution d’une application et, dans une moindre mesure, de son API, c’est un fait incontestable. C’est même semblable à l’évolution d’un produit apparemment complexe comme un langage de programmation, le design de l’URI devrait avoir moins de contraintes naturelles et il devrait être préservé dans le temps . Plus la durée de vie de l'application et de l'API est longue, plus l'engagement avec les utilisateurs de l'application et de l'API est important.

D'autre part, il est également difficile de prévoir toutes les ressources et leurs aspects qui seraient utilisés par le biais de l'API. Heureusement, il n’est pas nécessaire de concevoir l’API complète qui sera utilisée jusqu’à Apocalypse . Il suffit de définir correctement tous les points d'extrémité de la ressource et le schéma d'adressage de chaque ressource et instance de ressource.

Avec le temps, vous devrez peut-être ajouter de nouvelles ressources et de nouveaux attributs à chaque ressource particulière, mais la méthode suivie par les utilisateurs d'API pour accéder à des ressources particulières ne devrait pas changer une fois qu'un schéma d'adressage de ressource devient public et donc final.

Cette méthode s'applique aux sémantiques de verbes HTTP (par exemple, PUT doit toujours mettre à jour/remplacer) et aux codes de statut HTTP pris en charge dans les versions antérieures de l'API (ils devraient continuer à fonctionner de manière à ce que les clients API ayant fonctionné sans intervention humaine puissent continuer à fonctionner. comme ça).

De plus, l'intégration de la version de l'API dans l'URI perturberait le concept de l'hypermédia en tant que moteur de l'état de l'application (énoncé dans la thèse de Roy T. Fieldings) en ayant une adresse de ressource/URI qui changerait Je conclurais que les versions de l'API ne devaient pas être conservées longtemps dans les URI de ressources , ce qui signifie que les = (URI de ressources) Les utilisateurs d’API sur lesquels ils peuvent compter doivent être des liens permanents .

Bien sûr, il est possible d'incorporer la version de l'API dans l'URI de base mais uniquement pour des utilisations raisonnables et restreintes telles que le débogage d'une API client qui fonctionne avec la nouvelle version de l'API. Ces API versionnées doivent être limitées dans le temps et disponibles uniquement pour des groupes d'utilisateurs d'API limités (comme lors de bêtas fermés). Sinon, vous vous engagez là où vous ne devriez pas.

Quelques réflexions sur la maintenance des versions de l'API comportant une date d'expiration. Toutes les plateformes/langages de programmation couramment utilisés pour implémenter des services Web (Java, .NET, PHP, Perl, Rails, etc.) permettent de lier facilement le ou les points de terminaison de service Web à un URI de base. De cette façon, il est facile de rassembler et de conserver un ensemble de fichiers/classes/méthodes distincts entre les différentes versions de l'API .

Depuis les utilisateurs POV d’API, il est également plus facile de travailler avec une version d’API particulière et de la lier lorsque cela est évident, mais seulement pour un temps limité, c’est-à-dire pendant le développement.

À partir du POV du mainteneur d’API, il est plus facile de maintenir différentes versions d’API en parallèle en utilisant des systèmes de contrôle de code source qui fonctionnent principalement sur des fichiers en tant que plus petite unité de versioning (code source).

Cependant, avec les versions d'API clairement visibles dans l'URI, il y a une mise en garde: on peut également objecter à cette approche car l'historique de l'API devient visible/apparenté dans la conception de l'URI et est donc sujet aux changements dans le temps , ce qui va à l'encontre des recommandations de REST. Je suis d'accord!

Pour contourner cette objection raisonnable, vous devez implémenter la dernière version de l'API sous l'URI de base de l'API sans version. Dans ce cas, les développeurs de clients API peuvent choisir de:

  • développer contre la dernière version (en s’engageant à maintenir l’application en la protégeant contre les modifications éventuelles de l’API qui risqueraient de casser leur client API mal conçu ).

  • se lier à une version spécifique de l'API (ce qui devient apparent), mais seulement pour un temps limité

Par exemple, si API v3.0 est la version la plus récente de l'API, les deux suivants doivent être des alias (par exemple, se comporter de manière identique pour toutes les demandes d'API):

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

En outre, les clients API qui essaient encore de pointer sur l'API old doivent être informés de l'utilisation de la dernière version de l'API précédente si la version de l'API qu'ils utilisent est obsolète ou n'est plus supporté . Donc, accéder à l’un des URI obsolètes comme ceux-ci:

 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

doit renvoyer les codes d’état HTTP 30x qui indiquent une redirection utilisés conjointement avec l’en-tête HTTP Location redirigeant vers la version appropriée de URI de la ressource qui reste à être celui-ci:

http: // shonzilla/api/clients/1234

Il existe au moins deux codes d'état HTTP de redirection appropriés pour les scénarios de contrôle de version de l'API:

  • 1 Déplacé de façon permanente indiquant que la ressource avec un URI demandé est déplacée de manière permanente vers un autre URI (qui doit être un lien permanent d'instance de ressource qui ne contient pas d'informations de version d'API). Ce code de statut peut être utilisé pour indiquer une version d'API obsolète/non prise en charge, informant le client de l'API qu'un URI de version versionné a été remplacé par un permalien de ressource .

  • 2 trouvé indiquant que la ressource demandée est temporairement située à un autre emplacement, alors que l'URI demandé peut toujours être pris en charge. Ce code d’état peut être utile lorsque les URI sans version sont temporairement indisponibles et qu’une demande doit être répétée à l’aide de l’adresse de redirection (par exemple, en pointant sur l’URI avec la version APi intégrée) et que nous souhaitons dire aux clients de continuer à l’utiliser (par exemple, permaliens).

  • d'autres scénarios peuvent être trouvés dans chapitre Redirection 3xx de la spécification HTTP 1.1

683
Shonzilla

L'URL ne doit PAS contenir les versions. La version n'a rien à voir avec "l'idée" de la ressource que vous demandez. Vous devriez essayer de penser à l'URL comme étant un chemin d'accès au concept que vous souhaitez - et non comme vous voulez que l'élément soit renvoyé. La version dicte la représentation de l'objet, pas le concept de l'objet. Comme d'autres affiches l'ont dit, vous devriez spécifier le format (y compris la version) dans l'en-tête de la demande.

Si vous regardez la requête HTTP complète pour les URL qui ont des versions, cela ressemble à ceci:

(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>

L'en-tête contient la ligne contenant la représentation que vous demandez ("Accepter: application/xml"). C'est là que la version devrait aller. Tout le monde semble ignorer le fait que vous voudrez peut-être la même chose dans différents formats et que le client devrait pouvoir demander ce qu'il veut. Dans l'exemple ci-dessus, le client demande TOUT Représentation XML de la ressource - pas vraiment la représentation vraie de ce qu’elle veut. En théorie, le serveur pourrait renvoyer quelque chose de complètement différent de la demande, à condition qu'il s'agisse de XML et qu'il devrait être analysé pour se rendre compte de son erreur.

Une meilleure façon est:

(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>

En outre, disons que les clients pensent que le XML est trop détaillé et qu’ils veulent maintenant du JSON. Dans les autres exemples, vous devrez créer une nouvelle URL pour le même client. Vous obtiendrez ainsi:

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

(ou quelque chose de similaire). Quand en fait, chaque requête HTTP contient le format que vous recherchez:

(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"}
}

En utilisant cette méthode, vous avez beaucoup plus de liberté dans la conception et adhérez à l'idée originale de REST. Vous pouvez modifier les versions sans perturber les clients ou modifier progressivement les clients à mesure que les API changent. Si vous choisissez de ne plus prendre en charge une représentation, vous pouvez répondre aux demandes avec un code d'état HTTP ou des codes personnalisés. Le client peut également vérifier que le format de la réponse est correct et valider le code XML.

Il existe de nombreux autres avantages et j'en discute ici sur mon blog: http://thereisnorightway.blogspot.com/2011/02/versioning-and-types-in-resthttp-api.html

Un dernier exemple pour montrer à quel point l'insertion de la version dans l'URL est incorrecte. Supposons que vous souhaitiez obtenir des informations à l'intérieur de l'objet et que vous ayez défini le version de vos différents objets (les clients sont v3.0, les commandes sont v2.0 et l'objet shipto est v4.2). Voici l'URL désagréable que vous devez fournir au client:

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

Nous avons trouvé pratique et utile de mettre la version dans l'URL. Il est facile de dire ce que vous utilisez en un coup d'œil. Nous faisons alias/foo to/foo/(dernières versions) pour une facilité d'utilisation, des URL plus courtes/plus propres, etc., comme le suggère la réponse acceptée.

Garder la compatibilité en amont pour toujours est souvent très coûteux et/ou très difficile. Nous préférons donner un préavis de dépréciation, des redirections comme suggéré ici, des documents et d’autres mécanismes.

98
Yoav Shapira

Je conviens que la gestion des versions de la représentation des ressources suit mieux l'approche REST ... mais un gros problème avec les types MIME personnalisés (ou les types MIME qui ajoutent un paramètre de version) est le support insuffisant pour écrire dans Accept et Content. -Type En-têtes en HTML et JavaScript.

Par exemple, il n'est pas possible à IMO d'envoyer POST avec les en-têtes suivants dans les formulaires HTML5, afin de créer une ressource:

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

En effet, l'attribut HTML5 enctype est une énumération. Par conséquent, les valeurs autres que les types habituels application/x-www-formurlencoded, multipart/form-data et text/plain ne sont pas valides.

... Je ne suis pas sûr non plus qu'il soit pris en charge par tous les navigateurs en HTML4 (qui a un attribut encytpe plus laxiste, mais poserait un problème d'implémentation du navigateur pour savoir si le type MIME avait été transféré)

Pour cette raison, je pense maintenant que le moyen le plus approprié de passer à la version est via l'URI, mais j'accepte que ce n'est pas le bon.

46
Kevsy

Mettez votre version dans l'URI. Une version d'une API ne prend pas toujours en charge les types d'une autre. Par conséquent, l'argument voulant que les ressources soient simplement migrées d'une version à une autre est tout simplement faux. Ce n'est pas la même chose que passer d'un format XML à un format JSON. Les types peuvent ne pas exister ou ils peuvent avoir changé sémantiquement.

Les versions font partie de l'adresse de la ressource. Vous dirigez une API à une autre. Ce n'est pas RESTful de cacher l'adressage dans l'en-tête.

21
Sean O'Dell

Vous pouvez effectuer le contrôle de version dans une API REST à quelques endroits:

  1. Comme indiqué, dans l'URI. Cela peut être traitable et même esthétique si les redirections et autres sont bien utilisés.

  2. Dans l'en-tête Accept:, la version est donc dans le type de fichier. Comme 'mp3' vs 'mp4'. Cela fonctionnera également, bien que l’OMI fonctionne un peu moins bien que ...

  3. Dans la ressource elle-même. De nombreux formats de fichiers ont leur numéro de version intégré, généralement dans l'en-tête; Cela permet aux logiciels plus récents de "fonctionner" en comprenant toutes les versions existantes du type de fichier, tandis que les logiciels plus anciens peuvent émettre une raquette si une version non prise en charge (plus récente) est spécifiée. Dans le contexte d'une API REST, cela signifie que vos URI ne doivent jamais changer, mais uniquement votre réponse à la version particulière des données qui vous ont été transmises.

Je peux voir des raisons d'utiliser les trois approches:

  1. si vous aimez faire de nouvelles API "en vrac", ou pour les changements de version majeurs où vous souhaitez une telle approche.
  2. si vous voulez que le client sache avant de faire un PUT/POST s'il va fonctionner ou non.
  3. si cela ne pose pas de problème si le client doit faire son PUT/POST pour savoir s'il va fonctionner.
13
pjz

La gestion de la version de votre API REST est analogue à la gestion de la version de toute autre API. Des modifications mineures peuvent être effectuées sur place. Des modifications majeures peuvent nécessiter une toute nouvelle API. Le plus simple pour vous est de recommencer à zéro à chaque fois, c'est-à-dire lorsque la version de l'URL a tout son sens. Si vous voulez simplifier la vie du client, vous essayez de maintenir une compatibilité ascendante, ce que vous pouvez faire avec obsolète (redirection permanente), avec des ressources de plusieurs versions, etc. Ceci est plus complexe et demande plus d’efforts. Mais c’est aussi ce que REST encourage dans "Les adresses URI cool ne changent pas".

En fin de compte, c'est comme n'importe quelle autre conception d'API. Peser l'effort contre la convenance du client. Envisagez d'adopter un contrôle de version sémantique pour votre API, ce qui indique clairement à vos clients à quel point votre nouvelle version est compatible avec les versions antérieures.

8