Le paquet NuGet Microsoft.AspNetCore.Mvc.Versioning offre une approche robuste et flexible pour gérer les différentes itérations de vos points de terminaison REST. L'un de ses principaux avantages réside dans l'utilisation d'attributs déclaratifs directement sur les contrôleurs, ce qui simplifie grandement la maintenance du code. De plus, il permet d'informer automatiquement les clients lorsqu'ils requêtent une version obsolète ou inexistante.
Configuration des services de versionnage
Pour activer ces fonctionnalités, il est nécessaire de configurer les services lors du démarrage de l'application. Voici comment définir une version par défaut pour les requêtes non spécifiées et activer le rapport des versions prises en charge via le constructeur de l'application moderne :
var builder = WebApplication.CreateBuilder(args);
builder.Services.AddControllers();
builder.Services.AddApiVersioning(options =>
{
options.ReportApiVersions = true;
options.AssumeDefaultVersionWhenUnspecified = true;
options.DefaultApiVersion = new ApiVersion(1, 0);
});
var app = builder.Build();
app.MapControllers();
app.Run();
Remarque : Assurez-vous que votre version par défaut n'est pas marquée comme obsolète sur le contrôleur correspondant, afin d'éviter que les requêtes de vos clients ne soient rejetées par la stratégie de versinonage.
Versionnage par chaîne de requête
Le versionnage par paramètre d'URL est la méthode la plus directe et est supporté nativement. En ajoutant un paramètre comme ?api-version=1.0, le routeur dirige la requête vers le contrôleur approprié.
namespace MonProjet.Api.Controllers.V1
{
[ApiVersion("1.0")]
[Route("api/articles")]
[ApiController]
public class ArticlesController : ControllerBase
{
[HttpGet]
public IActionResult ObtenirArticles()
{
return Ok("Données de la version 1.0");
}
}
}
Pour introduire une version ultérieure tout en signalant l'obsolescence de l'ancienne, vous pouvez créer un nouveau contrôleur dans un espace de noms différent :
namespace MonProjet.Api.Controllers.V2
{
[ApiVersion("2.0")]
[ApiVersion("1.0", Deprecated = true)]
[Route("api/articles")]
[ApiController]
public class ArticlesController : ControllerBase
{
[HttpGet]
public IActionResult ObtenirArticles()
{
return Ok("Données de la version 2.0");
}
}
}
Si un client tente d'accéder à une version inexistante (par exemple 3.0), l'API renverra automatiquement un code d'état 400 Bad Request accompagné d'un message JSON détaillant les versions supportées.
Versionnage par en-tête HTTP
Si vous préférez ne pas surcharger l'URL avec des paramètres, l'utilisation des en-têtes HTTP est une excellente alternative. Il faut ajuster le lecteur de version dans la configuration pour cibler un en-tête personnalisé :
builder.Services.AddApiVersioning(opts =>
{
opts.ReportApiVersions = true;
opts.AssumeDefaultVersionWhenUnspecified = true;
opts.DefaultApiVersion = new ApiVersion(1, 0);
opts.ApiVersionReader = new HeaderApiVersionReader("X-Version-API");
});
Avec cette configuration, le client doit inclure l'en-tête X-Version-API: 2.0 dans sa requête pour accéder à la nouvelle itération, tout en conseravnt la même URL de base.
Versionnage par segment d'URL
L'intégration de la version directement dans le chemin de l'URL (ex: /api/v1/articles) nécessite l'utilisation du lecteur de segment d'URL et une adaptation des routes sur les contrôleurs.
builder.Services.AddApiVersioning(cfg =>
{
cfg.ReportApiVersions = true;
cfg.AssumeDefaultVersionWhenUnspecified = true;
cfg.DefaultApiVersion = new ApiVersion(1, 0);
cfg.ApiVersionReader = new UrlSegmentApiVersionReader();
});
Pour que la version par défaut fonctionne correctement lorsqu'aucun segment n'est fourni, il est crucial de définir une route de repli sur le contrôleur initial :
namespace MonProjet.Api.Controllers.V1
{
[ApiVersion("1.0", Deprecated = true)]
[Route("api/v{version:apiVersion}/articles")]
[Route("api/articles")] // Route de repli pour la version par défaut
[ApiController]
public class ArticlesController : ControllerBase
{
[HttpGet]
public IActionResult ObtenirArticles() => Ok("Version 1.0");
}
}
namespace MonProjet.Api.Controllers.V2
{
[ApiVersion("2.0")]
[Route("api/v{version:apiVersion}/articles")]
[ApiController]
public class ArticlesController : ControllerBase
{
[HttpGet]
public IActionResult ObtenirArticles() => Ok("Version 2.0");
}
}
Lorsqu'une requête est traitée, la réponse inclura l'en-tête api-deprecated-versions si la version appelée est marquée comme telle. Ce mécanisme informe explicitement les consommateurs de l'API qu'ils doivent planifier une migration vers une itération plus récente, ce qui s'avère particulièrement utile lors de la gestion de multiples clients externes.