Le versioning des API est devenu un enjeu majeur dans l’évolution d’applications modernes. Les APIs REST assurent la communication entre services, applications front-end, mobiles ou tierces.
Avec le temps, les besoins évoluent : nouveaux champs, formatage différent, amélioration de la structure des réponses… autant de changements qui risquent de casser les clients existants si aucune stratégie de versioning n’est en place.
C’est pourquoi Spring Boot offre plusieurs mécanismes solides et complémentaires pour maintenir des APIs robustes et évolutives.
Pourquoi versionner une API ?
Objectifs principaux :
- Assurer la compatibilité ascendante : une nouvelle version ne doit jamais casser les anciennes.
- Faire évoluer progressivement vos services, avec possibilité d'expérimentation.
- Clarifier les usages pour les consommateurs : chaque version est identifiable et documentée.
- Gérer plusieurs types de clients (web, mobile, partenaires externes).
Les approches classiques de versioning dans Spring Boot
Spring Boot propose depuis longtemps trois grandes approches :
- Version dans l’URL
- Version en paramètre de requête
- Version dans les headers HTTP
Pour illustrer ces différentes stratégies, nous utiliserons plusieurs versions d’un modèle User.
public class UserV1 {
private String name;
public UserV1(String name) { this.name = name; }
public String getName() { return name; }
public void setName(String name) { this.name = name; }
}
public class UserV2 {
private String firstName;
private String lastName;
public UserV2(String firstName, String lastName) {
this.firstName = firstName;
this.lastName = lastName;
}
public String getFirstName() { return firstName; }
public void setFirstName(String firstName) { this.firstName = firstName; }
public String getLastName() { return lastName; }
public void setLastName(String lastName) { this.lastName = lastName; }
}
public class UserV3 extends UserV2 {
private int age;
public UserV3(String firstName, String lastName, int age) {
super(firstName, lastName);
this.age = age;
}
public int getAge() { return age; }
public void setAge(int age) { this.age = age; }
}Versioning via URL
L’URL contient la version :/api/user/v1, /api/user/v2, etc.
Exemple :
@GetMapping("/v1")
public UserV1 getUserV1() {
return new UserV1("John Doe");
}
Avantages
- Très explicite
- Facile à tester
- Idéal pour les APIs publiques
Inconvénients
- Multiplication des endpoints
- Moins flexible en cas de nombreuses versions
Versioning via Query Parameter
La version est transmise comme paramètre :GET /api/user?version=1
Exemple :
@GetMapping(params = "version=1")
public UserV1 getUserQueryV1() { ... }
Avantages
- L’URL principale reste stable
- Simple à mettre en place
Inconvénients
- Moins RESTful
- Moins intuitif pour certains clients ou caches HTTP
Versioning via Header HTTP
Le client envoie un header du type :X-API-VERSION: 1
Exemple :
@GetMapping(path = "/header", headers = "X-API-VERSION=1")
public UserV1 getUserHeaderV1() { ... }
Avantages
- URLs propres
- Très utilisé dans les systèmes internes
Inconvénients
- Plus difficile à tester sans outils dédiés
- Moins transparent pour les développeurs juniors
Tableau comparatif des approches
| Approche | Exemple | Avantages | Inconvénients |
|---|---|---|---|
| URL | /api/user/v1 |
Explicite, simple | Multiplication des endpoints |
| Query param | /api/user?version=1 |
URL stable | Moins RESTful |
| Header | X-API-VERSION: 1 |
Propre, flexible | Test plus complexe |
Nouveauté : Versioning directement dans les annotations Spring (Spring Boot 4 & Spring Framework 7)
Depuis Spring Framework 7, une nouvelle approche a pointé le bout de son nez :
👉 le versioning directement intégré dans les annotations de mapping.
Cette méthode est plus centralisée et réduit la duplication d’URL ou de règles de routing.
Exemple :
@GetMapping(path = "/user", version = "4")
public UserV4 getUserV4() { ... }
@GetMapping(path = "/user", version = "5")
public UserV5 getUserV5() { ... }
Points forts
- La version est déclarée au même endroit que la route.
- Le code est plus lisible et moins répétitif.
- La documentation OpenAPI reflète automatiquement les différentes versions.
- Les URLs restent stables → idéal pour les clients mobiles.
Configuration nécessaire
Tu écrivais :
spring.mvc.apiversion.use.header=API-Version
Ce n’est plus la syntaxe actuelle.
La bonne configuration Spring 7 / Boot 4 est :
spring.mvc.api-version.strategy=header
spring.mvc.api-version.header-name=API-Version
Bonnes pratiques pour un versioning durable
1. Favoriser la compatibilité ascendante
Ne cassez aucune version existante sans période de transition.
2. Documenter chaque version
OpenAPI / Swagger 3.1 est devenu indispensable.
3. Déprécier progressivement
Annoncer une version comme deprecated 6 à 12 mois avant suppression.
4. Éviter la prolifération de versions
Au-delà de 3 versions actives en parallèle, les coûts explosent.
5. Automatiser les tests multi-versions
Testcontainers + Spring Cloud Contract font merveille.
Tout le code présent dans cet article est trouvable ici :