Versioning is an indispensable facet of the software development process. As your Web API evolves and new features get added, old ones might become deprecated or undergo substantial changes. Introducing these changes without a strategy can break existing clients and services that depend on your API. That’s where versioning comes into play.
In this article, we will explore different strategies to handle versioning in Web APIs, focusing primarily on ASP.NET Web API.
Why Versioning?
- Backward Compatibility: Older clients can continue to use the version they are compatible with.
- Smooth Transitions: Clients get ample time to migrate from an older version to a newer one.
- Clear Communication: Indicates API maturity and provides clear information about changes and updates.
Strategies for Versioning
1. URI Versioning
This is the most straightforward approach. The version information is directly embedded into the API’s URI.
Example:
https://api.example.com/v1/productshttps://api.example.com/v2/products
Pros:
- Easy to implement.
- Explicit, making it clear for consumers.
Cons:
- Not RESTful (theoretically, URIs should represent resources, not versions).
- Might lead to redundant routes.
2. Query String Versioning
Here, the version information is passed as a query parameter in the URL.
Example:
https://api.example.com/products?version=1https://api.example.com/products?version=2
Pros:
- Easy to implement and read.
- Allows the URI to remain consistent.
Cons:
- Can become cluttered if there are many query parameters.
3. Header Versioning
With this method, the version information is transmitted in the HTTP header.
Example:
Using a custom header:
api-version: 1api-version: 2
Or using the Accept header:
Accept: application/vnd.example.v1+jsonAccept: application/vnd.example.v2+json
Pros:
- Clean URLs.
- More RESTful compared to URI versioning.
- Provides flexibility, especially using media type versioning.
Cons:
- Not as explicit; clients need to know which header to set.
4. MediaType Versioning (Accept Header)
This involves sending the version information in the Accept header.
Example:
Accept: application/vnd.myapi.v1+jsonAccept: application/vnd.myapi.v2+json
Pros:
- Highly flexible.
- Adheres to REST principles.
Cons:
- More complicated than other methods.
Which Strategy to Choose?
The strategy you select will depend on your project’s requirements and the preferences of your development team:
- If you prefer clean and explicit URLs, go for URI versioning.
- For a blend of clean URIs and the simplicity of not messing with headers, query string versioning is a good choice.
- If you’d rather not alter the URL and are comfortable with headers, choose header versioning.
- For a more RESTful approach, and if you’re dealing with various media types, MediaType versioning might be best.
Implementing Versioning in ASP.NET Web API
Let’s break down the versioning approaches for ASP.NET Core Web API in a more detailed manner:
1. URI Versioning
Step-by-Step Implementation:
- Organize Controllers by Version:
- Create separate folders or namespaces for each version, for clarity.
- For our example, we’ll create
V1andV2folders.
- Define Controllers:
V1:
[ApiController]
[Route("api/v1/products")]
public class ProductsV1Controller : ControllerBase
{
[HttpGet]
public IActionResult Get()
{
return Ok("Version 1 products.");
}
}
V2:
[ApiController]
[Route("api/v2/products")]
public class ProductsV2Controller : ControllerBase
{
[HttpGet]
public IActionResult Get()
{
return Ok("Version 2 products with additional features.");
}
}
- Testing: Navigate to
/api/v1/productsand/api/v2/productsto see the respective version outputs.
2. Query String Versioning
Step-by-Step Implementation:
- Install Necessary Package:
Install-Package Microsoft.AspNetCore.Mvc.Versioning
- Configure Versioning:
In Startup.cs within ConfigureServices:
services.AddApiVersioning(o =>
{
o.DefaultApiVersion = new ApiVersion(1, 0);
o.ReportApiVersions = true;
o.ApiVersionReader = new QueryStringApiVersionReader("version");
});
- Define Controllers:
Use the [ApiVersion] attribute to define which versions each controller supports.
V1:
[ApiController]
[Route("api/products")]
[ApiVersion("1.0")]
public class ProductsV1Controller : ControllerBase
{
[HttpGet]
public IActionResult Get()
{
return Ok("Version 1 products.");
}
}
V2:
[ApiController]
[Route("api/products")]
[ApiVersion("2.0")]
public class ProductsV2Controller : ControllerBase
{
[HttpGet]
public IActionResult Get()
{
return Ok("Version 2 products with additional features.");
}
}
- Testing: Access versions via
/api/products?version=1.0and/api/products?version=2.0.
3. Header Versioning
Step-by-Step Implementation:
- Configure Versioning:
In Startup.cs:
services.AddApiVersioning(o =>
{
o.ApiVersionReader = new HeaderApiVersionReader("api-version");
});
- Define Controllers:
Similar to the Query String method. Just set up your controllers with the [ApiVersion] attribute.
- Testing:
Use a tool like Postman or use curl to send requests. Set a header with the key api-version and values 1.0 or 2.0.
4. MediaType Versioning (Accept Header)
Step-by-Step Implementation:
- Configure Versioning:
In Startup.cs:
services.AddApiVersioning(o =>
{
o.ApiVersionReader = new MediaTypeApiVersionReader();
});
- Define Controllers:
Just as with the previous methods, use the [ApiVersion] attribute to define versions.
- Testing:
Send a request setting the Accept header to application/vnd.yourcompany.v1+json for version 1, and application/vnd.yourcompany.v2+json for version 2.
In all these methods, you can further enhance versioning by using the ApiVersionNeutral attribute for actions or controllers that don’t need versioning, or by combining multiple versioning methods using the ApiVersionReader.Combine() method.
Remember to always update documentation for your API consumers whenever a new version is released.


Leave a comment