Decoupling API Versions From Codebase Versions

When developing a package(any piece of reusable code, like a class library to be loaded or a web service that’s accessible through HTTP) that has a published API it is necessary to have a clear separation between the API version and the codebase version of the package.

The API is what is exposed from the package for the users to consume, this should be documented clearly and the module should have thorough tests included that tests the entire published API to assert it conforms to the documented. This ensures that when a new version of the package has been rolled out.

When there is a need to redefine the API specification such that it is not compatible with the current specification, a new version of the API should be specified and this is how multiple versions of the API come into play, because there would be some consumers of the package that are relying on the current API specification and until they all have migrated to the new version both versions of the API must be made available.

The codebase version comes from the development team’s software configuration management (SCM) system, from the point of view of the consumer’s of the package this version has no significance, they should only care about the API version because that’s the only way the consumers interact with the package, through the API - the codebase can be completely rewritten in a different technology stack but if the API remains the same then the consumers shouldn’t notice a change.

The codebase version is of more interest to the maintainers of the package, the change management platform for example, which could be different from the development team. A useful (and quite common) convention for versioning codebase is Semantic Versioning. When adopting this versioning then the major version of the codebase will be linked to the API version. So for example if there is a need to redefine API version 1 into version 2, then the codebase will move from version 1.y.z to 2.0.0

There are 3 essentials that are important to get right when the plan is to have several packages made available for several consuming applications;

  1. Upgrades to the packages should cause no disruptions to the consuming applications
  2. Upgrades to the packages should need no changes to the consuming applications
  3. There should be only one version of the codebase running in the live system

To elaborate the ideas, let’s consider a package which is available as a web service that is runnig at http://api.package.com and its codebase version is 2.1.0 which means its API version is 2. But to support consuming applications still using version 1 of the API there needs to be a way of requesting the API version in the HTTP request.

There are a couple of ways of doing this, for example if requesting for version 2 of the API;

HTTP headers can be used

GET http://api.package.com/resource
Accept: application/vnd.pacakger+v2

Or the URL can be used

GET http://api.package.com/v2/resource

Although the former method is the most elegant and recommended method (See this discussion) most popular and established APIs use the latter method (See the section called “Versioning strategies in popular REST APIs” in this post) most likely due to the ease of use from a variety of HTTP clients some of which are limited in terms of what you can set in the headers.

As you can see from the point of view of the consuming applications, the codebase version is not exposed at all, that URL could be running version 2.0.4, 2.8.1 or 3.2.0 of the codebase but the application doesn’t care, all it needs is version 2 of the API

From the package manager’s point of view in managing the version of the package, they don’t really care about the API version, they only care about the codebase version. When rolling out a new version they roll it out in a separate location which is not made avaialable to the consuming applications (like http://api-test.package.com) run some bundled tests that assert the new version maintains compatibility with the documented API and switch the live URL (http://api.package.com) to use the new version.

Hence there is a clear separation between the two version systems, API version which is only visible to the developers of consuming applications and codebase version which is only visible to the package managers.

By including bundled tests that run with every upgrade of the package to assert the API is not broken point 1 above is achieved. By removing any instance of the codebase version in the URL made available to developers of consuming applications, point 2 is achieved and by supporting multiple API versions in the same codebase point 3 is achieved.

 
comments powered by Disqus