In systems that use RESTful APIs, one of the main concerns is ensuring that software evolution does not break compatibility with clients already in production. When we change an API (by adding new features, modifying behaviors, or fixing bugs), those changes can affect clients still using earlier versions. Therefore, versioning an API is essential to ensure service stability and continuity.
In this article, we’ll explore how to implement API versioning in ASP.NET Core, demonstrating different approaches to ensure compatibility across versions and controlled API evolution.
Why Version an API?
API versioning is a crucial practice for scalable and sustainable software development. It offers several advantages:
Compatibility with existing clients: Versioning ensures that clients using an older version of the API will not be impacted by breaking changes.
Controlled evolution: As new features are added or improvements are made to the API, versioning allows them to be introduced without breaking previous versions.
Stability: Versioning guarantees that older versions of the API remain stable and functional, while new versions can be tested and adjusted without interruptions.
Documentation and maintenance: Versions help document changes over time, making maintenance and onboarding of new developers or teams easier.
API Versioning Approaches in ASP.NET Core
There are several ways to version an API in ASP.NET Core. The appropriate method depends on your project’s context and needs. Below, we’ll explore the main approaches:
Implementing Versioning
To implement API version control, we’ll need the following package:
.NET CLI
dotnet add package Asp.Versioning.Mvc.ApiExplorer
Package-Manager
Install-Package Asp.Versioning.Mvc.ApiExplorer
This package provides the necessary API versioning features, allowing you to document your versions.
Now, let’s create two controllers: one for version 1.0 and another for version 2.0 of our API. These controllers will share the same route, but with different versions.
Version 1.0 Controller
using Asp.Versioning;
using Microsoft.AspNetCore.Mvc;
namespace APITest.Controllers.v1;
[ApiController]
[Route("api/v{version:apiVersion}/products")]
[ApiVersion("1.0")]
public class ProdutosV1Controller : ControllerBase
{
[HttpGet]
public IActionResult GetProdutosV1()
{
return Ok(new { Message = "Version 1.0 - Products" });
}
}
Here, we use the [ApiVersion("1.0")] attribute to specify that this controller belongs to version 1.0. The API route includes the version, allowing it to be specified directly in the URL.
Version 2.0 Controller
using Asp.Versioning;
using Microsoft.AspNetCore.Mvc;
namespace APITest.Controllers.v2;
[ApiController]
[Route("api/v{version:apiVersion}/products")]
[ApiVersion("2.0")]
public class ProductsV2Controller : ControllerBase
{
[HttpGet]
public IActionResult GetProductsV2()
{
return Ok(new { Message = "Version 2.0 - Products with new features" });
}
}
You can organize controllers into separate folders to keep things tidy.
Now that the controllers are ready, let’s configure the Program.cs file:
builder.Services.AddEndpointsApiExplorer();
builder.Services.AddApiVersioning()
.AddMvc()
.AddApiExplorer(setup =>
{
setup.GroupNameFormat = "'v'VVV";
setup.SubstituteApiVersionInUrl = true;
});
AddEndpointsApiExplorerenables dynamic API documentation generation.AddApiVersioningadds versioning support to the API.AddMvcenables controller and routing features needed for an API.AddApiExplorerenriches the API documentation with versioning details.GroupNameFormat = "'v'VVV"formats group names asv1,v2,v3, etc.SubstituteApiVersionInUrl = trueallows API version to be substituted directly into the route URL.
When running the application and accessing the endpoints for each version, we will get different responses.
Configuring Swagger for Versioning
With versioned endpoints available via URLs, if we use Swagger, we won’t be able to select the desired API version unless Swagger is configured properly.
Step 1: Create a Configuration Class
Create a folder called SwaggerConfig (or any name you prefer) and add a new file named ConfigureSwaggerGenOptions.cs. Then, create the class as below:
public class ConfigureSwaggerGenOptions : IConfigureOptions
{
private readonly IApiVersionDescriptionProvider _apiVersionDescriptionProvider;
public ConfigureSwaggerGenOptions(IApiVersionDescriptionProvider apiVersionDescriptionProvider)
{
_apiVersionDescriptionProvider = apiVersionDescriptionProvider;
}
public void Configure(SwaggerGenOptions options)
{
foreach (var description in _apiVersionDescriptionProvider.ApiVersionDescriptions)
{
options.SwaggerDoc(description.GroupName, CreateOpenApiInfo(description));
}
}
private static OpenApiInfo CreateOpenApiInfo(ApiVersionDescription description)
{
var info = new OpenApiInfo()
{
Title = "API Versioning",
Version = description.ApiVersion.ToString()
};
if (description.IsDeprecated)
{
info.Description += " (deprecated)";
}
return info;
}
}
IApiVersionDescriptionProviderprovides version metadata used by Swagger.SwaggerDocregisters a Swagger document per version.CreateOpenApiInfobuilds metadata such as title and version.If the version is deprecated, it’s marked accordingly.
Step 2: Update Program.cs to Use the Configuration
Register the configuration class and set up Swagger UI:
builder.Services.ConfigureOptions();
Then configure Swagger UI:
app.UseSwaggerUI(options =>
{
var version = app.Services.GetRequiredService();
foreach (var description in version.ApiVersionDescriptions)
{
options.SwaggerEndpoint($"/swagger/{description.GroupName}/swagger.json", $"Web API - {description.GroupName.ToUpper()}");
}
});
This configures Swagger UI to display documentation and provide interactive testing for each API version.
Conclusion
In this article, we showed how to implement API versioning in ASP.NET Core using the Asp.Versioning library and how to configure Swagger to generate interactive documentation for multiple API versions. This approach allows your API to evolve without breaking compatibility with earlier versions, simplifying maintenance and providing a better experience for developers. With this setup, you can now version and test your API efficiently using Swagger UI.