877 votes

Quelles sont les meilleures pratiques en matière de versions d'API ?

Existe-t-il un mode d'emploi ou des bonnes pratiques connus pour le versionnement des API REST des services web ?

J'ai remarqué que AWS effectue le versioning par l'URL du point de terminaison . S'agit-il du seul moyen ou existe-t-il d'autres moyens d'atteindre le même objectif ? S'il existe plusieurs moyens, quels sont les avantages de chacun d'entre eux ?

682voto

Shonzilla Points 5277

C'est une question à la fois bonne et délicate. Le thème de la La conception de l'URI est en même temps la partie la plus importante d'une API REST et Il s'agit donc d'un un engagement à long terme envers les utilisateurs de cette API .

Étant donné que l'évolution d'une application et, dans une moindre mesure, de son API est une réalité et qu'elle est même similaire à l'évolution d'un produit apparemment complexe tel qu'un langage de programmation, l'équipe d'experts de la Commission européenne a été chargée d'élaborer un plan d'action pour l'évolution de l'application. Conception de l'URI devrait avoir moins contraintes naturelles et il doivent être préservées dans le temps . Plus la durée de vie de l'application et de l'API est longue, plus l'engagement envers les utilisateurs de l'application et de l'API est important.

D'autre part, il est difficile de prévoir toutes les ressources et leurs aspects qui seront consommés par l'intermédiaire de l'API. Heureusement, il n'est pas nécessaire de concevoir l'ensemble de l'API qui sera utilisée jusqu'à ce qu'elle soit utilisée. Apocalypse . Il suffit de définir correctement tous les points d'extrémité des ressources et le schéma d'adressage de chaque ressource et instance de ressource.

Au fil du temps, il se peut que vous deviez ajouter de nouvelles ressources et de nouveaux attributs à chaque ressource particulière, mais la méthode suivie par les utilisateurs de l'API pour accéder à une ressource particulière ne doit pas changer une fois que le schéma d'adressage d'une ressource devient public et donc définitif.

Cette méthode s'applique à la sémantique des verbes HTTP (par exemple, PUT doit toujours mettre à jour/remplacer) et aux codes d'état HTTP qui sont pris en charge dans les versions antérieures de l'API (ils doivent continuer à fonctionner de manière à ce que les clients de l'API qui ont fonctionné sans intervention humaine puissent continuer à travailler de la même manière).

En outre, étant donné que l'intégration de la version de l'API dans l'URI perturberait le concept de l'hypermédia comme moteur de l'état de l'application (comme indiqué dans la thèse de doctorat de Roy T. Fieldings) en ayant une adresse de ressource/URI qui changerait au fil du temps, je conclurais que Les versions de l'API ne doivent pas être conservées longtemps dans les URI des ressources ce qui signifie que les URI de ressources dont les utilisateurs de l'API peuvent dépendre doivent être des permaliens .

Bien sûr, il est possible d'intégrer la version de l'API dans l'URI de base pero uniquement pour des utilisations raisonnables et restreintes telles que le débogage d'un client API 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 limités d'utilisateurs d'API (comme pendant les bêtas fermées). Sinon, vous vous engagez là où vous ne le devriez pas.

Quelques réflexions concernant la maintenance des versions de l'API qui ont une date d'expiration. Toutes les plateformes/langages de programmation couramment utilisés pour mettre en œuvre les services web (Java, .NET, PHP, Perl, Rails, etc.) permettent de lier facilement le(s) point(s) d'arrivée des services web à un URI de base. De cette manière, il est facile de rassembler et conserver un ensemble de fichiers/classes/méthodes distincts selon les différentes versions de l'API .

Du point de vue des utilisateurs de l'API, il est également plus facile de travailler et de se lier à une version particulière de l'API lorsque cela est évident, mais seulement pour une durée limitée, c'est-à-dire pendant le développement.

Du point de vue du responsable de l'API, il est plus facile de maintenir différentes versions de l'API en parallèle en utilisant des systèmes de contrôle de la source qui travaillent principalement sur des fichiers en tant que plus petite unité de versionnement (du code source).

Cependant, les versions de l'API étant clairement visibles dans l'URI, il y a une mise en garde : on peut également s'opposer à cette approche puisque L'historique de l'API devient visible/aparent dans la conception de l'URI et est donc susceptible de changer au fil du temps ce qui va à l'encontre des lignes directrices de REST. Je suis d'accord !

La façon de contourner cette objection raisonnable est de mettre en œuvre 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 de l'API peuvent choisir l'une ou l'autre option :

  • développent en fonction de la dernière version (s'engageant à maintenir l'application en la protégeant contre d'éventuelles modifications de l'API qui pourraient briser leur client API mal conçu ).

  • se lier à une version spécifique de l'API (qui devient apparente) mais seulement pour une durée limitée

Par exemple, si API v3.0 est la dernière version de l'API, les deux suivantes devraient être des alias (c'est-à-dire qu'elles se comportent de la même manière pour toutes les demandes d'API) :

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

En outre, les clients de l'API qui essaient encore de pointer vers le fichier ancien L'API doit être informée de l'utilisation de la dernière version de l'API, si la version de l'API qu'ils utilisent est obsolète ou n'est plus prise en charge . Ainsi, l'accès à l'un des URI obsolètes tels que 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 l'un des éléments suivants 30x Codes d'état HTTP indiquant une redirection qui sont utilisés en conjonction avec Location En-tête HTTP qui redirige vers la version appropriée de l'URI de la ressource qui reste celle-ci :

http://shonzilla/api/customers/1234

Il existe au moins deux codes d'état HTTP de redirection qui conviennent aux scénarios de versionnement de l'API :

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

  • 302 Trouvé indiquant que la ressource demandée se trouve temporairement à un autre endroit, 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 en utilisant l'adresse de redirection (par exemple en pointant vers l'URI avec la version APi intégrée) et que nous voulons indiquer aux clients de continuer à l'utiliser (c.-à-d. les permaliens).

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

273voto

jeremyh Points 2162

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 devez essayer de considérer l'URL comme un chemin vers le concept que vous souhaitez - et non pas comme la manière dont vous voulez que l'élément soit retourné. La version dicte la représentation de l'objet, pas le concept de l'objet. Comme d'autres l'ont dit, vous devriez spécifier le format (y compris la version) dans l'en-tête de la requête.

Si vous regardez la requête HTTP complète pour les URL qui ont des versions, elle 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 qui contient la représentation que vous demandez ("Accept : application/xml"). C'est là que la version doit être placée. Tout le monde semble ignorer le fait que vous pouvez vouloir la même chose dans des formats différents et que le client devrait pouvoir demander ce qu'il veut. Dans l'exemple ci-dessus, le client demande ANY Représentation XML de la ressource - qui n'est pas vraiment la véritable représentation de ce qu'elle veut. Le serveur pourrait, en théorie, renvoyer quelque chose qui n'a rien à voir avec la demande, tant qu'il s'agit de XML, et il faudrait l'analyser pour se rendre compte qu'il est erroné.

Une meilleure façon de procéder est la suivante :

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

De plus, supposons que les clients trouvent que le XML est trop verbeux et qu'ils veulent maintenant du JSON à la place. Dans les autres exemples, il faudrait avoir une nouvelle URL pour le même client, ce qui donnerait :

(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). En réalité, toutes les requêtes HTTP contiennent 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 vous adhérez en fait à l'idée originale de REST. Vous pouvez changer de version sans perturber les clients, ou changer progressivement les clients au fur et à mesure que les API sont modifiées. Si vous décidez de ne plus prendre en charge une représentation, vous pouvez répondre aux demandes par un code d'état HTTP ou des codes personnalisés. Le client peut également vérifier que la réponse est dans le bon format et valider le XML.

Il existe de nombreux autres avantages http://thereisnorightway.blogspot.com/2011/02/versioning-and-types-in-resthttp-api.html

Un dernier exemple pour montrer qu'il n'est pas bon de mettre la version dans l'URL. Supposons que vous souhaitiez obtenir un élément d'information à l'intérieur de l'objet, et que vous ayez versionné vos différents objets (les clients sont v3.0, les commandes sont v2.0, et l'objet shipto est v4.2). Voici la mauvaise URL 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/

98voto

Yoav Shapira Points 671

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

Conserver à jamais la compatibilité ascendante est souvent prohibitif en termes de coûts et/ou très difficile. Nous préférons donner un préavis de dépréciation, par des redirections comme celles suggérées ici, des docs, et d'autres mécanismes.

46voto

Kevsy Points 290

Je suis d'accord pour dire que le versionnement de la représentation de la ressource 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 la mauvaise prise en charge de l'écriture dans les en-têtes Accept et Content-Type en HTML et en JavaScript.

Par exemple, il n'est pas possible IMO de 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, la norme HTML5 enctype est une énumération, donc tout ce qui n'est pas l'attribut habituel application/x-www-formurlencoded , multipart/form-data y text/plain ne sont pas valables.

...et je ne suis pas sûr qu'il soit pris en charge par tous les navigateurs en HTML4 (qui a un attribut encytpe plus laxiste, mais la question de savoir si le type MIME a été transmis relève de l'implémentation du navigateur).

C'est pourquoi j'estime désormais que la manière la plus appropriée d'établir une version est l'URI, mais je reconnais que ce n'est pas la manière la plus "correcte".

21voto

Sean Points 143

Mettez votre version dans l'URI. Une version d'une API ne prend pas toujours en charge les types d'une autre, de sorte que l'argument selon lequel les ressources sont simplement migrées d'une version à l'autre est tout simplement erroné. Ce n'est pas la même chose que de passer du format XML au format JSON. Il se peut que les types n'existent pas ou qu'ils aient changé sur le plan sémantique.

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

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X