J'ai cherché comment gérer les versions d'une API REST à l'aide de Spring 3.2.x, mais je n'ai rien trouvé de facile à maintenir. Je vais d'abord expliquer le problème que j'ai, puis une solution ... mais je me demande si je réinvente la roue ici.
Je veux gérer la version en fonction de l'en-tête Accept, et par exemple si une demande a l'en-tête Accept application/vnd.company.app-1.1+json
, je veux que spring MVC la transmette à la méthode qui gère cette version. Et comme toutes les méthodes d'une API ne changent pas dans la même version, je ne veux pas accéder à chacun de mes contrôleurs et changer quoi que ce soit pour un gestionnaire qui n'a pas changé entre les versions. Je ne veux pas non plus avoir la logique de déterminer quelle version utiliser dans le contrôleur lui-même (en utilisant des localisateurs de service) car Spring découvre déjà la méthode à appeler.
Donc, pris une API avec les versions 1.0, à 1.8 où un gestionnaire a été introduit dans la version 1.0 et modifié dans la v1.7, je voudrais gérer cela de la manière suivante. Imaginez que le code se trouve à l'intérieur d'un contrôleur et qu'il y ait du code capable d'extraire la version de l'en-tête. (Ce qui suit n'est pas valide au printemps)
@RequestMapping(...)
@VersionRange(1.0,1.6)
@ResponseBody
public Object method1() {
// so something
return object;
}
@RequestMapping(...) //same Request mapping annotation
@VersionRange(1.7)
@ResponseBody
public Object method2() {
// so something
return object;
}
Cela n'est pas possible au printemps car les 2 méthodes ont la même RequestMapping
annotation et Spring ne se charge pas. L'idée est que l' VersionRange
annotation peut définir une plage de versions ouverte ou fermée. La première méthode est valable des versions 1.0 à 1.6, tandis que la seconde pour la version 1.7 et suivantes (y compris la dernière version 1.8). Je sais que cette approche se rompt si quelqu'un décide de passer la version 99.99, mais c'est quelque chose avec lequel je suis d'accord.
Maintenant, comme ce qui précède n'est pas possible sans une refonte sérieuse du fonctionnement du ressort, je pensais bricoler la façon dont les gestionnaires correspondent aux demandes, en particulier pour écrire les miens ProducesRequestCondition
, et y inclure la gamme de versions. Par exemple
Code:
@RequestMapping(..., produces = "application/vnd.company.app-[1.0-1.6]+json)
@ResponseBody
public Object method1() {
// so something
return object;
}
@RequestMapping(..., produces = "application/vnd.company.app-[1.7-]+json)
@ResponseBody
public Object method2() {
// so something
return object;
}
De cette façon, je peux avoir des plages de versions fermées ou ouvertes définies dans la partie produit de l'annotation. Je travaille sur cette solution maintenant, avec le problème que je devais encore remplacer certaines classes de base Spring MVC ( RequestMappingInfoHandlerMapping
, RequestMappingHandlerMapping
et RequestMappingInfo
), ce que je n'aime pas, car cela signifie un travail supplémentaire chaque fois que je décide de passer à une version plus récente de printemps.
J'apprécierais toute réflexion ... et surtout toute suggestion de faire cela d'une manière plus simple et plus facile à maintenir.
Éditer
Ajouter une prime. Pour obtenir la prime, veuillez répondre à la question ci-dessus sans suggérer d'avoir cette logique dans le contrôleur lui-même. Spring a déjà beaucoup de logique pour sélectionner la méthode de contrôleur à appeler, et je veux utiliser cela.
Modifier 2
J'ai partagé le POC original (avec quelques améliorations) dans github: https://github.com/augusto/restVersioning
produces={"application/json-1.0", "application/json-1.1"}