API Versioning

See versioning chapter in Wildermuth’s Web API Design slides One Drive.

Move the version with a ‘v’ prefix all the way to the left in the URL so that it has the highest scope (e.g. /v1/dogs).

Use a simple ordinal number - v1, v2, and so on. Don’t use the dot notation like v1.2 because it implies a granularity of versioning that doesn’t work well with APIs, it’s an interface not an implementation. Make the version mandatory.

type example info pro con
URL path https://api.stormpath.com/v1
http://api.tumblr.com/v2/user/
http://.../api/v1/Customers?type=Current&id=123
http://.../api/v2/CurrentCustomers/123
version embedded in URI path
everything after v subject to change
Simple to segregate old APIs for backwards compatibility a lot of client changes on version upgrade
increases URI surface to support(tech debt), upgraded v2 and former v1 bug fixes
Uri parameter http://api.netflix.com/catalog/titles/series/70023522?v=1.5
http://.../api/Customers
http://.../api/Customers?v=2.1
semantically same with URI path versioning without version => latest
Little client change as versions mature
surprise clients with changes not expected
Media Type/Content Negotiation application/foo+json;application&v=1
Content Type: application/vnd.github.1.param+json
Accept: application/myapp.v1.customer.json
Accept: vnd.myapp.v1.customer
Instead of using standard MIME types, use custom.
Can include information in Accept Header
Alternatively can create own MIME type.
Increasingly popular because separated from the surface area of the API itself
Packages API and Resource Versioning in one
Removes versioning from API so clients don’t have to change
Can encourage increased versioning which causes more code churning
Request/Custom Header Azure x-ms-version: 2011-08-18
x-MyApp-Version: 2.1
Should be a header value that is only of value to your API
Common to use API Date instead of number
Separates Versioning from API call signatures
Not tied to resource versioning (e.g. Content Type)
Adds complexity - adding headers isn’t easy on all platforms

Abstract

from Implementing an API in ASP.NET Web API by Shawn Wildermuth on Pluralsight

So, what do we mean by API Versioning? Once you expose an API through Web API, or really any REST-based API technology, it is done. You have customers and users that rely on it so you can’t change it. You have an implicit contract between you and these users and customers, those developers out there that have developed their applications against your API, which means that API can’t go away. But, of course, the requirements of what you’re trying to build are likely to change, so you need to have a way to evolve them without breaking the implicit contract between you and those developers.

API Versioning isn’t Product Versioning, so you’re not just going to release a new version of the API every time you release a new product version. With luck, you’re going to do less API Versioning than you are going to do Product Versioning, but there’s going to be cases where you’re going to need evolve and do both. It is typically a bad idea to tie the two concepts together.

So, the problem with API versioning is that it is very different from typical code versioning (assemblies). You’re going to be exposing out, in most cases, multiple versions of your API within the same ASP.NET project. So you have to have a way to deal with that versioning. Your API needs to support both new users that are going to use the latest version, as well as keep happy those developers that use the earlier versions of your API. You can’t really do side-by-side deployment. You’re going to be creating and supporting different versions of the API going forward. At some point, you may be able to sunset certain versions of the API, but you have to give developers a lot of notice that they’ll have to change their code. This need to have both versions in the same code base means you’re going to have similar functionality in different parts of your code base, and then have to have a way for Web API to detect which version the users are using, and have them come in.

Even more difficult is they may be using the original API you released, but you may be able to actually forward users to the new version of the API, and that’ll be fine. And so, the versioning may not be the entire API changes.

Creating A Versioned Controller

  // CountingKsAuthorizeAttribute : AuthorizationFilterAttribute
#if DEBUG 
 define DISABLE_SECURITY
#endif
// also mock CountingKsIdentityService
Thread.CurrentPrincipal.Identity.Name
// extend model class
MeasureV2Model : MeasureModel
// separate controlller class
public class MeasuresV2Controller : BaseApiController
// Some of the other techniques have a MeasuresController inside of a V1, and a V2, and a V3 namespace.
// WebApiConfig.Register (HttpConfiguration cfg)
cfg.Routes.MapHttpRoute(name: "Food",
    routeTemplate: "api/v1/nutrition/foods/{foodid}",
    defaults: new { controller="foods", ...}
);
CustomControllerSelector : System.Web.HttpDispatcher.DefaultHttpControllerSelector
// web api cfg (URL path)
cfg.Services.Replace(typeof(IHttpControllerSelector), typeof(CustomControllerSelector));
// unspecified params in urlhelper links are represented as query params
HttpUtility.ParseQueryString
GetVersionFromQueryString (HttpRequestMessage request)
// versioning with a version header
GetVersionFromHeader (HttpRequestMessage request)
request.Headers.Contains(X-CountingKs-Version)
request.Headers.GetValues(X-CountingKs-Version).FirstOrDefault()
// Versioning with The Accept Header
// Accept: application/json; version=2
request.Headers.Accept.First(mime => mime.MediaType == "application/json").Parameters.Where(p => p.Name == "version")
// own custom mime type
static void CreateMediaTypes (JsonMediaTypeFormatter jsonFormatter)
"application/vnd.countingks.measure.v2+json"
jsonFormatter.SupportedMediaTypes.Add(new MediaTypeHeaderValue(...))

Packages

  • SDammann.WebApi.Versioning, 2.8.0, Library for API versioning support in Microsoft ASP.NET Web API
  • Microsoft/aspnet-api-versioning a set of libraries which add service API versioning to ASP.NET Web API, OData with ASP.NET Web API, and ASP.NET Core.
    • ASP.NET Core Versioned API Explorer with Swagger Startup
    • ASP.NET Web API with OData quick start