API Versioning is the practice of having multiple endpoints for the same thing but having different return objects, different entry objects, or even various upgrades for the process. This looks complex but is relatively straightforward. For example, You have a REST Endpoint that returns Todo information. In the beginning, your Todo had only a description, but later on, the Todo also has a category, and you need to distinguish between each modification. You can change the endpoint so that you can get the new Todo with the description and category. What if you still need to give support to the oldest Todo?
I’m using Postman, so I can request and Swagger for that as well. I created an API application using .Net 5. I also added all the layers needed for the Clean Architecture, Application, Application.Contract, Domain, and Infrastructure.
You need to install this ->
Install-Package Microsoft.AspNetCore.Mvc.Versioning -Version 5.0.0
in your API application. Also, in your startup file, add this code->
public void ConfigureServices(IServiceCollection services)
{ …
services.AddApiVersioning(options => {
options.AssumeDefaultVersionWhenUnspecified = true; });
…
}
public void Configure(IApplicationBuilder app, IWebHostEnvironment env) {
…
app.UseApiVersioning();
…
Let create two controllers, one for each version. In the beginning, we had the TodoItemController, and then we needed to create the TodoItemV2Controller.
TodoItemController
TodoItemV2Controller
As you can see, I also created two services, one for each version. I did this because your application will be more organized, and besides, with this approach, you follow the SOLID principles. I’m using Automapper so I can convert the object TodoItemCreatoDto into TodoItem(Domain object) and the object TodoItemDtoV2 into TodoItem(Domain object).
Top view for the logic behind Automapper and saving the TodoItem.
With this logic, the application is ready to have the versioning by URI. You have access to both versions changing the /v{1,2} argument ->
https://localhost:5001/api/v{1 or 2}/TodoItem
This approach is the most popular method and is easy to set up. It doesn’t come without drawbacks. And doesn’t imply a default version, so you are forced to update the URIs.
This one is identical with URI Path, but you don’t have to define routes in this case. You only need to add the new QueryStringApiVersionReader.
services.AddApiVersioning(setup =>
{
setup.DefaultApiVersion = new ApiVersion(1, 0);
setup.AssumeDefaultVersionWhenUnspecified = true;
setup.ReportApiVersions = true;
setup.ApiVersionReader = new QueryStringApiVersionReader(“version”);
});
If you want to keep the URI intact, you can send the version by the header. For example, if you want to use a non-default version of the API, you need to send the Api-Version request header value. For this in the startup file you just need to add a new HeaderApiVersionReader.
services.AddApiVersioning(setup =>
{
setup.DefaultApiVersion = new ApiVersion(1, 0);
setup.AssumeDefaultVersionWhenUnspecified = true;
setup.ReportApiVersions = true;
setup.ApiVersionReader = new HeaderApiVersionReader(“Api-Version”);
});
In the Postman, you need to add the Api-Version and the value.
You can the version using the Accept header. The Accept header can be used to control the format of the request it can handle. These days, the most common Accept value is the media type of application/json. We can use versioning with our media types, too. To use the Accept header, you need to add the new MediaTypeApiVersionReader.
services.AddApiVersioning(setup =>
{
setup.DefaultApiVersion = new ApiVersion(1, 0);
setup.AssumeDefaultVersionWhenUnspecified = true;
setup.ReportApiVersions = true;
setup.ApiVersionReader = new MediaTypeApiVersionReader(“v”);
});
Using the Microsoft.AspNetCore.Mvc.Versioning NuGet package, you aren’t forced into using a single versioning method. For example, you can have multiple methods and allow the User(Postman in our case) to choose what they prefer. The ApiVersionReader supports a static Combine method that allows you to specify multiple ways to read versions.
Like this
services.AddApiVersioning(options =>
{
options.DefaultApiVersion = new ApiVersion(1, 0);
options.AssumeDefaultVersionWhenUnspecified = true;
options.ReportApiVersions = true;
options.ApiVersionReader = ApiVersionReader.Combine(
new HeaderApiVersionReader(“Api-Version”),
new QueryStringApiVersionReader(“version”));
});