Introduction
Versioning is key when developing APIs, especially if they're exposed outside of your team or organization. What would you do if an API your application consumed suddenly changed input parameters or changed its output? Let me guess: Probably scream out loud in frustration..
So please dont be that guy who break applications in other organizations. Version your APIs! This is how.
The basics
Lets start with the basics. A version number consist, normally, of four numbers Major.Minor.Patch.Revision
. I´ve rarly or never seen Revision
or Patch
being used as part of an API version, probably because they refer to internal changes and not the contract being exposed to the consumers. Lets cover all four anyway.
Major
You should bump the Major
version if you have any breaking changes in the contract between your application and consumers of your API. An example would be that you deprecated a method or changed mandatory input parameters to a method that would affect the consuming part.
Minor
Minor changes to your application which does not break the integration between your system and consuming applications. This might be bug fixes or that you´ve added extra data in the response back to the consuming application.
Patch
Internal bugfixes in your application.
Revision
Usually a number added by the build server to differentiate release across the versions.
But how?
Microsoft have released a NuGet package solely for the purpose of API versioning. You can install it to your project from the command line
dotnet add package Microsoft.AspNetCore.Mvc.Versioning --version 5.0.0
Once the download is complete, find the method ConfigureServices
in Startup.cs
and add the following statement services.AddApiVersioning();
. The next step is to find your controller and map that specific controller to an api version. Attribute the controller with [ApiVersion("1.0")]
in order to do so.
Now you can navigate to your endpoint and make sure that you specify which version of the api to use by adding ?api-version=1.0
at the end of your url.
Change versioning schemas
If you don´t like the default syntax of adding a query parameter to specify the api-version, you can just change it.
You got several options to change the versioning schema, implement it yourself or including a pre-defined class from the NuGet-package.
This is done by adding an implementation of IApiVersionReader
in the AddApiVersioning
method. You can also choose to implement this yourself if the specific use case isn´t covered by the implementations provided by Microsoft.
If you want to use the version as a segment of the url, you can add an instance of UrlSegmentApiVersionReader
in the example above. If you choose this implementation you'll have to change the route for all of your controllers to support this. This version reader uses string interpolation to inject the variable to your route. The route for the example below would be /api/v1.0/products
.
Default api-version
If your consumers navigate to the api without specifying the api-version, they'll get an error message telling them to specify it. You can, however, assume that they want to consume the default version of the api by specifying so in the AddApiVersioning
-method:
What about swagger, is it supported?
Yes, you document your version with swagger, but it's way more of hazzle than first expected. These are the steps:
1. Install Microsoft.AspNetCore.Mvc.Versioning.ApiExplorer
dotnet add package Microsoft.AspNetCore.Mvc.Versioning.ApiExplorer --version 5.0.0
2. Implement the method AddVersionedApiExplorer
in ConfigureServices
3. Update the AddSwaggerGen
method to list Api title and version
4. Update method UseSwaggerUI
in the Configure
method
When you run the application, you should see that the swagger definition shows up in your browser.
Deprecate versions of your API.
You probably want to deprecate your old APIs as new ones are created. It would also be nice to report back to the consumer which of the versions that are deprecated. This can be achieved by setting the property ReportApiVersions
in services.AddApiVersioning(..)
to true
Then mark the controller as deprecated like this:
If we have several API controllers with the same route, but different versions, the http header in the response will report back the supported and deprecated versions.
Wrapping up
Version is key when designing APIs. The NuGet package has alot more functionality than demonstrated above. I encourage you to try it out and play around with the different schemas and functionality in this library.
You can find the complete source code here: https://github.com/Thorstensen/api-versioning