Versionner une API REST

1. Le problème

L'évolution d'une API REST est un problème difficile - un problème pour lequel de nombreuses options sont disponibles. Cet article décrit certaines de ces options.

2. Qu'y a-t-il dans le contrat?

Avant toute chose, nous devons répondre à une question simple: quel est le contrat entre l'API et le client?

2.1. Les URI font-ils partie du contrat?

Considérons d'abord la structure URI de l'API REST - cela fait-il partie du contrat? Les clients doivent-ils mettre en signet, coder en dur et généralement s'appuyer sur les URI de l'API?

Si tel est le cas, alors l'interaction du Client avec le Service REST ne serait plus pilotée par le Service lui-même, mais par ce que Roy Fielding appelle des informations hors bande :

Une API REST doit être saisie sans aucune connaissance préalable au-delà de l'URI initial (signet) et de l'ensemble de types de supports standardisés qui conviennent au public visé… Un échec ici implique que les informations hors bande conduisent à une interaction au lieu de l'hypertexte.

Il est donc clair que les URI ne font pas partie du contrat ! Le client ne doit connaître qu'un seul URI - le point d'entrée de l'API. Tous les autres URI doivent être découverts lors de la consommation de l'API.

2.2. Les types de médias font-ils partie du contrat?

Qu'en est-il des informations sur le type de support utilisées pour les représentations des ressources - font-elles partie du contrat entre le client et le service?

Afin de réussir à consommer l'API, le client doit avoir une connaissance préalable de ces types de supports . En fait, la définition de ces types de supports représente l'intégralité du contrat.

Par conséquent, c'est là que le service REST doit se concentrer le plus:

Une API REST devrait consacrer presque tout son effort de description à la définition du ou des types de médias utilisés pour représenter les ressources et à la gestion de l'état de l'application, ou à la définition de noms de relations étendus et / ou de balisage hypertexte pour les types de médias standard existants.

Ainsi , les définitions de type médias font partie du contrat et devrait être une connaissance préalable du client qui consomme l'API. C'est là que la normalisation entre en jeu.

Nous avons maintenant une bonne idée de ce qu'est le contrat, passons à la manière de résoudre réellement le problème de version.

3. Options de haut niveau

Discutons maintenant des approches de haut niveau de la gestion des versions de l'API REST:

  • Gestion des versions URI - version de l'espace URI à l'aide des indicateurs de version
  • Gestion des versions du type de média - version la représentation de la ressource

Lorsque nous introduisons la version dans l'espace URI, les représentations des ressources sont considérées comme immuables. Ainsi, lorsque des modifications doivent être introduites dans l'API, un nouvel espace URI doit être créé.

Par exemple, supposons qu'une API publie les ressources suivantes - utilisateurs et privilèges:

//host/v1/users //host/v1/privileges

Maintenant, considérons qu'un changement radical dans l' API des utilisateurs nécessite l'introduction d'une deuxième version:

//host/v2/users //host/v2/privileges

Lorsque nous versons le type de média et étendons la langue, nous passons par la négociation de contenu basée sur cet en-tête. L'API REST utiliserait des types de supports MIME de fournisseur personnalisés au lieu de types de supports génériques tels que application / json . Nous allons versionner ces types de médias au lieu des URI.

Par exemple:

===> GET /users/3 HTTP/1.1 Accept: application/vnd.myname.v1+json <=== HTTP/1.1 200 OK Content-Type: application/vnd.myname.v1+json { "user": { "name": "John Smith" } }

Nous pouvons consulter cet article «Types de médias personnalisés pour les API Rest» pour plus d'informations et des exemples à ce sujet.

Ce qu'il est important de comprendre ici, c'est que le client ne fait aucune hypothèse sur la structure de la réponse au-delà de ce qui est défini dans le type de média.

C'est pourquoi les types de supports génériques ne sont pas idéaux. Ceux - ci ne fournissent pas suffisamment d'informations sémantiques et obligent le client à utiliser des conseils supplémentaires pour traiter la représentation réelle de la ressource.

Une exception à cela consiste à utiliser une autre méthode d'identification unique de la sémantique du contenu, comme un schéma XML.

4. Avantages et inconvénients

Maintenant que nous avons un concept clair de ce qui fait partie du contrat entre le client et le service, ainsi qu'un aperçu de haut niveau des options de version de l'API, discutons des avantages et des inconvénients de chaque approche.

Premièrement, l' introduction d'identificateurs de version dans l'URI conduit à une très grande empreinte d'URI. Cela est dû au fait que tout changement de rupture dans l'une des API publiées introduira une toute nouvelle arborescence de représentations pour l'ensemble de l'API. Au fil du temps, cela devient un fardeau à entretenir ainsi qu'un problème pour le client - qui a maintenant plus d'options à choisir.

Les identificateurs de version dans l'URI sont également extrêmement rigides . Il n'y a aucun moyen de simplement faire évoluer l'API d'une seule ressource ou d'un petit sous-ensemble de l'API globale.

Comme nous l'avons mentionné précédemment, il s'agit d'une approche tout ou rien. Si une partie de l'API passe à la nouvelle version, l'ensemble de l'API doit évoluer avec elle. Cela fait également de la mise à niveau des clients de la v1 à la v2 une entreprise majeure - ce qui entraîne des mises à niveau plus lentes et des périodes de temporisation beaucoup plus longues pour les anciennes versions.

La mise en cache HTTP est également une préoccupation majeure en matière de gestion des versions.

Du point de vue des caches proxy au milieu, chaque approche présente des avantages et des inconvénients. Si l'URI est versionné, le cache devra conserver plusieurs copies de chaque ressource - une pour chaque version de l'API. Cela met une charge sur le cache et diminue le taux de réussite du cache car différents clients utiliseront des versions différentes.

De plus, certains mécanismes d'invalidation du cache ne fonctionneront plus. Si le type de support est celui qui est versionné, alors le client et le service doivent prendre en charge l'en-tête HTTP Vary pour indiquer qu'il existe plusieurs versions mises en cache.

Du point de vue de la mise en cache client , cependant, la solution qui verse le type de média implique un peu plus de travail que celle où les URI contiennent l'identificateur de version. En effet, il est tout simplement plus facile de mettre en cache quelque chose lorsque sa clé est une URL qu'un type de média.

Terminons cette section en définissant quelques objectifs (tout droit sortis d'API Evolution):

  • garder les changements compatibles hors des noms
  • éviter les nouvelles versions majeures
  • rend les modifications rétrocompatibles
  • penser à la compatibilité ascendante

5. Modifications possibles de l'API

Ensuite, examinons les types de modifications apportées à l'API REST - elles sont présentées ici:

  • changements de format de représentation
  • changements de ressources

5.1. Ajout à la représentation d'une ressource

La documentation de format du type de support doit être conçue en gardant à l'esprit la compatibilité ascendante. Plus précisément, un client doit ignorer les informations qu'il ne comprend pas (ce que JSON fait mieux que XML).

Désormais, l' ajout d'informations dans la représentation d'une ressource ne cassera pas les clients existants si ceux-ci sont correctement implémentés.

Pour continuer notre exemple précédent, l'ajout du montant dans la représentation de l' utilisateur ne sera pas un changement radical:

{ "user": { "name": "John Smith", "amount": "300" } }

5.2. Suppression ou modification d'une représentation existante

La suppression, le changement de nom ou la restructuration générale des informations dans la conception des représentations existantes est un changement radical pour les clients. C'est parce qu'ils comprennent déjà et s'appuient sur l'ancien format.

C'est là qu'intervient la négociation de contenu. Pour de telles modifications, nous pouvons ajouter un nouveau type de média MIME de fournisseur.

Continuons avec l'exemple précédent. Disons que nous voulons diviser le nom de l' utilisateur en prénom et nom :

===> GET /users/3 HTTP/1.1 Accept: application/vnd.myname.v2+json <=== HTTP/1.1 200 OK Content-Type: application/vnd.myname.v2+json { "user": { "firstname": "John", "lastname": "Smith", "amount": "300" } }

En tant que tel, cela représente un changement incompatible pour le client - qui devra demander la nouvelle représentation et comprendre la nouvelle sémantique. Cependant, l'espace URI restera stable et ne sera pas affecté.

5.3. Changements sémantiques majeurs

These are changes in the meaning of the Resources, the relations between them or what the map to in the backend. This kind of changes may require a new media type, or they may require publishing a new, sibling Resource next to the old one and making use of linking to point to it.

While this sounds like using version identifiers in the URI all over again, the important distinction is that the new Resource is published independently of any other Resources in the API and will not fork the entire API at the root.

The REST API should adhere to the HATEOAS constraint. According to this, most of the URIs should be DISCOVERED by Clients, not hardcoded. Changing such an URI should not be considered an incompatible change. The new URI can replace the old one and Clients will be able to re-discover the URI and still function.

It's worth noting however that, while using version identifiers in the URI is problematic for all of these reasons, it is not un-RESTful in any way.

6. Conclusion

This article tried to provide an overview of the very diverse and difficult problem of evolving a REST Service. We discussed the two common solutions, advantages and disadvantages of each one, and ways to reason about these approaches in the context of REST.

L'article conclut en présentant le cas de la deuxième solution - la gestion des versions des types de médias tout en examinant les modifications possibles d'une API RESTful.

L'implémentation complète de ce didacticiel se trouve dans le projet GitHub.

7. Lectures complémentaires

Habituellement, ces ressources de lecture sont liées tout au long de l'article, mais dans ce cas, il y en a tout simplement trop de bonnes:

    • Les API REST doivent être basées sur l'hypertexte
    • Évolution de l'API
    • Liaison pour une API HTTP
    • Stratégies de compatibilité