Comment faire une version des URI REST

111

Quelle est la meilleure façon de version des URI REST? Actuellement, nous avons un numéro de version dans l'URI lui-même, c'est-à-dire.

http://example.com/users/v4/1234/

pour la version 4 de cette représentation.

La version appartient-elle à la queryString? c'est à dire.

http://example.com/users/1234?version=4

Ou le contrôle de version est-il mieux réalisé d'une autre manière?

Mike Pone
la source

Réponses:

34

Je dirais que le faire partie de l'URI lui-même (option 1) est préférable car la v4 identifie une ressource différente de la v3. Les paramètres de requête comme dans votre deuxième option peuvent être mieux utilisés pour transmettre des informations (de requête) supplémentaires liées à la demande , plutôt qu'à la ressource .

Zef Hemel
la source
11
La question est: s'agit-il d'une RESSOURCE différente dont nous discutons? Ou une représentation différente de cette ressource? REST fait-il une distinction entre la représentation et la ressource?
Cheeso
1
@Cheeso - L'OP indique qu'il s'agit d'une représentation différente plutôt que d'une ressource différente, d'où ma réponse.
Greg Beech
Cela a été répondu plus en détail avant ici stackoverflow.com/q/389169/104261
Taras Alenin
+1 pour "Les paramètres de requête comme dans votre deuxième option peuvent être mieux utilisés pour transmettre des informations (de requête) supplémentaires liées à la demande, plutôt qu'à la ressource"
andy
Pour différentes représentations, je pense que vous devriez utiliser des en-têtes comme "Accepter", alors le client peut spécifier au serveur "J'accepte uniquement la version 4" et le serveur peut répondre avec cette représentation. Si aucune acceptation n'est envoyée, la dernière version est fournie.
Carlos Verdes
190

Ne versez pas les URL, car ...

  • vous cassez les permaliens
  • Les changements d'URL se propageront comme une maladie à travers votre interface. Que faites-vous des représentations qui n'ont pas changé mais qui indiquent la représentation qui a changé? Si vous modifiez l'url, vous cassez d'anciens clients. Si vous laissez l'url, vos nouveaux clients risquent de ne pas fonctionner.
  • La gestion des versions des types de supports est une solution beaucoup plus flexible.

En supposant que votre ressource renvoie une variante de application / vnd.yourcompany.user + xml, tout ce que vous avez à faire est de créer un support pour un nouveau type de support application / vnd.yourcompany.userV2 + xml et grâce à la magie de la négociation de contenu votre v1 et Les clients v2 peuvent coexister pacifiquement.

Dans une interface RESTful, la chose la plus proche d'un contrat est la définition des types de supports échangés entre le client et le serveur.

Les URL que le client utilise pour interagir avec le serveur doivent être fournies par le serveur intégré dans les représentations précédemment récupérées. La seule URL qui doit être connue du client est l'URL racine de l'interface. L'ajout de numéros de version aux URL n'a de valeur que si vous construisez des URL sur le client, ce que vous n'êtes pas censé faire avec une interface RESTful.

Si vous avez besoin de modifier vos types de médias qui briseront vos clients existants, créez-en un nouveau et laissez vos URL tranquilles!

Et pour les lecteurs qui disent actuellement que cela n'a aucun sens si j'utilise application / xml et application / json comme types de média. Comment sommes-nous censés les versions? Tu n'es pas. Ces types de supports sont pratiquement inutiles pour une interface RESTful à moins que vous ne les analysiez en utilisant le téléchargement de code, auquel cas le contrôle de version est un point discutable.

Darrel Miller
la source
66
Pour aborder les puces. 1. vous ne rompez pas les liens perma, car les permaliens sont liés à une version spécifique 2. Si tout est versionné, ce n'est pas un problème. Les anciennes URL peuvent toujours fonctionner. Idéalement, vous ne voudriez pas qu'une URL version 4 renvoie une association à une ressource version 3. 3. Peut
Mike Pone
10
Imaginez si, lors de la mise à niveau vers une nouvelle version d'un navigateur Web, tous vos favoris marqués se sont cassés! Rappelez-vous que conceptuellement, l'utilisateur enregistre un lien vers une ressource et non vers une version d'une représentation d'une ressource.
Darrel Miller
11
@Gili Afin de satisfaire l'exigence d'une API REST d'être auto-descriptive, il est nécessaire que l'en-tête de type de contenu fournisse la description sémantique complète du message. En d'autres termes, votre type de média est votre contrat de données. Si vous livrez application / xml ou application / json, vous ne dites rien au client sur ce qui est contenu dans ce XML / Json. L'instant auquel une application cliente atteint dans un extrait / Client / Nom que vous créez un couplage basé sur des informations qui ne figurent pas dans le message. L'élimination du couplage hors bande est essentielle pour atteindre RESTfulness.
Darrel Miller
6
@Gili Le client ne doit avoir aucune connaissance préalable des URL de l'API autres que l'URL racine. Vous ne devez pas lier les formats de représentation à des URL spécifiques. Quand il s'agit de choisir des types de supports, vous devez vraiment choisir entre un format spécifique comme application / vnd.mycompany.myformat + xml ou un format standardisé comme XHtml, Atom, RDF, etc.
Darrel Miller
4
Est-il judicieux de mettre la version de l'API dans un champ d'en-tête séparé? Comme ceci: Acceptez: application / com.example.myapp + json; version = 1.0
Erik
21

Ah, je remets mon vieux chapeau grincheux.

Du point de vue de ReST, cela n'a aucune importance. Pas une saucisse.

Le client reçoit un URI qu'il souhaite suivre et le traite comme une chaîne opaque. Mettez-y ce que vous voulez, le client n'a aucune connaissance d'un identifiant de version dessus.

Ce que le client sait, c'est qu'il peut traiter le type de média, et je conseillerai de suivre les conseils de Darrel. De plus, je pense personnellement que le besoin de changer le format utilisé dans une architecture reposante 4 fois devrait apporter d'énormes signes avant-coureurs indiquant que vous faites quelque chose de très mal, et contourner complètement la nécessité de concevoir votre type de support pour la résilience au changement.

Mais de toute façon, le client ne peut traiter qu'un document avec un format qu'il peut comprendre, et suivre les liens qu'il contient. Il doit connaître les relations de lien (les transitions). Donc, ce qui est dans l'URI est complètement hors de propos.

Personnellement, je voterais pour http: // localhost / 3f3405d5-5984-4683-bf26-aca186d21c04

Un identifiant parfaitement valide qui empêchera tout autre développeur client ou personne de toucher le système pour se demander s'il faut mettre la v4 au début ou à la fin d'un URI (et je suggère que, du point de vue du serveur, vous ne devriez pas avoir 4 versions, mais 4 types de supports).

SerialSeb
la source
Que faire si la représentation doit changer de manière significative et ne sera pas rétrocompatible?
Mike Pone
1
En concevant votre type de média de manière extensible, par exemple en utilisant des espaces de noms et un xsd extensible, ou des formats XML existants comme l'atome, cela devrait être évitable. Si vous devez vraiment le faire, un autre type de média est la voie à suivre.
SerialSeb
1
J'aime cette réponse tout à fait valable, mais je pense que l'URI proposé est plus pour démontrer le point que pour un scénario réel dans lequel vous voulez des URI «piratables».
Dave Van den Eynde
10

Vous ne devez PAS mettre la version dans l'URL, vous devez mettre la version dans l'en-tête d'acceptation de la demande - voir mon message sur ce fil:

Bonnes pratiques pour la gestion des versions d'API?

Si vous commencez à coller des versions dans l'URL, vous vous retrouvez avec des URL idiotes comme celle-ci: http://company.com/api/v3.0/customer/123/v2.0/orders/4321/

Et il y a un tas d'autres problèmes qui s'insinuent également - voir mon blog: http://thereisnorightway.blogspot.com/2011/02/versioning-and-types-in-resthttp-api.html

Jeremyh
la source
11
Désolé, mais je ne pense pas que vous vous retrouviez avec des URL idiotes comme celle-ci. Vous associez les numéros de version à une ressource particulière ou (pire) à une représentation particulière. Ce serait idiot, OMI. Vous effectuez plutôt une version de l'API, de sorte que vous n'aurez jamais plus d'une version dans l'URI.
fool4jesus
3

Il existe 4 approches différentes pour la gestion des versions de l'API:

  • Ajout de la version au chemin URI:

    http://example.com/api/v1/foo
    
    http://example.com/api/v2/foo
    

    Lorsque vous avez un changement de rupture, vous devez incrémenter la version comme: v1, v2, v3 ...

    Vous pouvez implémenter un contrôleur dans votre code comme ceci:

    @RestController
    public class FooVersioningController {
    
    @GetMapping("v1/foo")
    public FooV1 fooV1() {
        return new FooV1("firstname lastname");
    }
    
    @GetMapping("v2/foo")
    public FooV2 fooV2() {
        return new FooV2(new Name("firstname", "lastname"));
    }
    
  • Demander la gestion des versions des paramètres:

    http://example.com/api/v2/foo/param?version=1
    http://example.com/api/v2/foo/param?version=2
    

    Le paramètre de version peut être facultatif ou obligatoire selon la manière dont vous souhaitez que l'API soit utilisée.

    La mise en œuvre peut être similaire à ceci:

    @GetMapping(value = "/foo/param", params = "version=1")
    public FooV1 paramV1() {
        return new FooV1("firstname lastname");
    }
    
    @GetMapping(value = "/foo/param", params = "version=2")
    public FooV2 paramV2() {
        return new FooV2(new Name("firstname", "lastname"));
    }
    
  • Passer un en-tête personnalisé:

    http://localhost:8080/foo/produces
    

    Avec en-tête:

    headers[Accept=application/vnd.company.app-v1+json]
    

    ou:

    headers[Accept=application/vnd.company.app-v2+json]
    

    Le plus grand avantage de ce schéma est principalement la sémantique: vous n'encombrez pas l'URI de quoi que ce soit à voir avec le contrôle de version.

    Implémentation possible:

    @GetMapping(value = "/foo/produces", produces = "application/vnd.company.app-v1+json")
    public FooV1 producesV1() {
        return new FooV1("firstname lastname");
    }
    
    @GetMapping(value = "/foo/produces", produces = "application/vnd.company.app-v2+json")
    public FooV2 producesV2() {
        return new FooV2(new Name("firstname", "lastname"));
    }
    
  • Modification des noms d'hôte ou utilisation des passerelles API:

    Essentiellement, vous déplacez l'API d'un nom d'hôte à un autre. Vous pourriez même simplement appeler cette construction une nouvelle API avec les mêmes ressources.

    Vous pouvez également le faire en utilisant les passerelles API.

Javier C.
la source
2

Si les services REST nécessitent une authentification avant utilisation, vous pouvez facilement associer la clé / jeton API à une version d'API et effectuer le routage en interne. Pour utiliser une nouvelle version de l'API, une nouvelle clé API peut être requise, liée à cette version.

Malheureusement, cette solution ne fonctionne que pour les API basées sur l'authentification. Cependant, il garde les versions hors des URI.

UberSteve
la source
2

Je voulais créer des API versionnées et j'ai trouvé cet article très utile:

http://blog.steveklabnik.com/posts/2011-07-03-nobody-understands-rest-or-http

Il y a une petite section sur "Je veux que mon API soit versionnée". Je l'ai trouvé simple et facile à comprendre. Le point crucial est d'utiliser le champ Accepter dans l'en-tête pour transmettre les informations de version.

Asma Zubair
la source
1

J'inclurais la version comme valeur facultative à la fin de l'URI. Cela peut être un suffixe comme / V4 ou un paramètre de requête comme vous l'avez décrit. Vous pouvez même rediriger le / V4 vers le paramètre de requête afin de prendre en charge les deux variantes.

Paul Morgan
la source
1

Si vous utilisez des URI pour la gestion des versions, le numéro de version doit se trouver dans l'URI de la racine de l'API, de sorte que chaque identificateur de ressource puisse l'inclure.

Techniquement, une API REST ne rompt pas par les changements d'URL (le résultat de la contrainte d'interface uniforme). Il ne casse que lorsque la sémantique associée (par exemple un vocabulaire RDF spécifique à une API) change d'une manière non rétrocompatible (rare). Actuellement, beaucoup de personnes n'utilisent pas de liens de navigation (contrainte HATEOAS) et de vocabulaire pour annoter leurs réponses REST (contrainte de message auto-descriptive), c'est pourquoi leurs clients se cassent.

Les types MIME personnalisés et la gestion des versions de type MIME n'aident pas, car le fait de placer les métadonnées associées et la structure de la représentation dans une chaîne courte ne fonctionne pas. Ofc. les métadonnées et la structure changeront fréquemment, et donc le numéro de version aussi ...

Donc, pour répondre à votre question, la meilleure façon d'annoter vos demandes et réponses avec des vocabulaires ( Hydra , données liées ) et d'oublier le versionnage ou de ne l'utiliser que par des changements de vocabulaire non rétrocompatibles (par exemple si vous souhaitez remplacer un vocabulaire par un autre).

inf3rno
la source
0

Je vote pour faire cela en type mime mais pas en URL. Mais la raison n'est pas la même que les autres gars.

Je pense que l'URL doit être unique (à l'exception de ces redirections) pour localiser la ressource unique. Donc, si vous acceptez /v2.0dans les URL, pourquoi ce n'est pas le cas /ver2.0ou /v2/ou /v2.0.0? Ou même -alphaet -beta? (alors cela devient totalement le concept de semver )

Ainsi, la version en type mime est plus acceptable que l'URL.

Yarco
la source