Use Case
You want to upgrade your existing API with a new version and some customers can't accommodate those new APIs. Customers who can't accommodate the latest APIs should be able to use the old versions and customers who can accommodate the latest API version should able to use the latest one. So a single code base here should host both versions.
NuGet Dependencies
You need to add the below dependencies in your Web API project
- Microsoft.AspNetCore.Mvc.Versioning - A service API versioning library for Microsoft ASP.NET Core
- Microsoft.AspNetCore.Mvc.Versioning.ApiExplorer - Discovering metadata such as the list of API-versioned controllers and actions, and their URLs and allowed HTTP methods
- Swashbuckle.AspNetCore - Swagger tools for documenting APIs built on ASP.NET Core
Code Changes in Controller
Attributes for Controller Class
The below attributes show that versions 1 and 2 are supported by the controller class and also define a route including the version number
- [ApiVersion("1")]
- [ApiVersion("2")]
- [ApiController]
- [Route("api/v{version:apiVersion}/[controller]")]
- public class WeatherForecastController : ControllerBase
- {
Attributes for Actions
Below MapToApiVersion attribute is showing what version number each of the actions supports.
- [HttpGet]
- [MapToApiVersion("1")]
- [Route("Weather")]
- public IEnumerable<WeatherForecast> GetWeatherV1()
- {
-
-
- [HttpGet]
- [MapToApiVersion("2")]
- [Route("Weather")]
- public IEnumerable<WeatherForecast> GetWeatherV2()
- {
Custom Classes for Swagger
Below classes are defined with swagger configuration and swagger default behavior.
- ConfigureSwaggerOptions
This class has been derived from IConfigureOptions<SwaggerGenOptions> and defines the basic configuration for Swagger to add documents for each API version
- SwaggerDefaultValues
This class has been derived from IOperationFilter and is adding support to load swagger documents based on the version selected
Code Changes in Startup.cs
Modify ConfigureServices()
The below lines will be added to ConfigureServices() method to initialize API Version & API Version Explorer libraries and also to register the above-mentioned custom classes. Please notice that we made version 1 as the default version.
- services.AddApiVersioning(options =>
- {
- options.DefaultApiVersion = new ApiVersion(1, 0);
- options.AssumeDefaultVersionWhenUnspecified = true;
- options.ReportApiVersions = true;
- });
-
- services.AddVersionedApiExplorer(options =>
- {
-
-
- options.GroupNameFormat = "'v'VVV";
-
-
-
- options.SubstituteApiVersionInUrl = true;
- });
- services.AddTransient<IConfigureOptions<SwaggerGenOptions>, ConfigureSwaggerOptions>();
- services.AddSwaggerGen(options => options.OperationFilter<SwaggerDefaultValues>());
Modify Configure()
The below code will be adding Swagger and SwaggerUI support. It also defines the swagger UI end points to browse for each API version.
-
- app.UseSwagger();
-
-
-
- app.UseSwaggerUI(
- options =>
- {
-
- foreach (var description in provider.ApiVersionDescriptions)
- {
- options.SwaggerEndpoint($"/swagger/{description.GroupName}/swagger.json", description.GroupName.ToUpperInvariant());
- }
- });
Run Web API with Swagger UI as Default
Let us run the application after modifying the below line inside launchSettings.json, which will make swagger as the default UI for the Web API project.
- "WeatherWebAPI": {
- "commandName": "Project",
- "launchBrowser": true,
- "launchUrl": "swagger",
- "environmentVariables": {
- "ASPNETCORE_ENVIRONMENT": "Development"
- },
- "applicationUrl": "https://localhost:5001;http://localhost:5000"
- },
You will notice that default version 1 swagger has been loaded and once it executes this version from the UI itself, you will get the response as expected below.
Now change the version from the UI itself as below and notice that the entire swagger definition has been changed to version 2. Once executing, you will get the ex[ected response from version 2 of the API.
This is the way to host multiple versions of APIs in a single code base. I uploaded the source code here for you to play around with. You can remove the docker file in it, if you have issues with docker and just try to run it locally.