There is a considerable amount of confusion and debate around the topic of versioning REST APIs. The opinions range all the way from don’t version your APIs (Roy Fielding) to version using HTTP headers to placing it in the URI and probably everything in between. Indeed, giants in the modern computing era like Microsoft, Amazon, Twitter, Salesforce, to name a few, each have their own way of handling this topic. As is often the case, reality is more nuanced than the words that reflect them.
To Version or not to Version
Roy Fielding in one article (https://www.infoq.com/articles/roy-fielding-on-versioning/) has this to say when talking about versioning REST resources:
My point was that there is no need to anticipate such world-breaking changes with a version ID. We have the hostname for that.
It is my inference that what Roy Fielding is saying is that REST resources don’t need to be versioned because the hostname in the URL used to locate these resources, is sufficient to disambiguate the different versions. In other words, he is advocating the use of a different hostname to serve up different versions of a resource. Seen in this light, the URI of the resource therefore does indeed become version independent.
The use of a service mesh composed of 100s or 1000s of microservices is now increasingly popular as development moves to a cloud native and scale out model. In this approach, each service defines well defined contracts exposed via a REST API interface (an RPC interface could also be used to expose these contracts). In an environment where services are expected to have little to no downtime (cloud) it is not unusual for multiple versions of a service to be running concurrently. It should be pretty obvious that managing hostnames at this scale quickly becomes unwieldy.
Therefore, an alternate approach that pushes the responsibility of the hostname lookup from the infrastructure (DNS lookups) to the application (API Gateway) is beneficial since the API gateway can be scaled out by virtue of being part of the application. In this model, the versioning information is part of the URL that immediately follows the hostname. The actual resource that the service sees is still version agnostic just as it would if it were handled in the hostname.
An API versioning proposal
Seen in this light, the problem of versioning comes down to where to capture the version information in the URL. At Nutanix, as we transition into becoming a multi-product company, versioning considerations of the API platform become extremely important. We’re standardizing on the APIs that we expose on the platform by following these simple steps:
- Introduce a semantic versioning model, v<family>.<revision>.<type><number> to distinguish different versions an API, where family and revision are integers and type is either alpha or beta;
- Ensure that compatibility is never broken within a family. This is a guarantee from the platform. As long as an API consumer consumes an API from within a family, the client will not be impacted by any change/upgrade of the server;
- Publish SDKs for each product/version combination, that encapsulate URIs of the API endpoints freeing clients from needing to deal with versions explicitly; and
- Use Hypermedia (HATEOAS principle) to expose links to related resources.
The API versioned scheme to be followed by Nutanix looks like this:
Of these parts, the api, <
namespace>, and <
version> portions of the URL are consumed by the API gateway and the rest of the endpoint (<
module> onwards) is handed off to the service for further routing.
Putting the version in the URI we believe has the following advantages:
- Readability – it is very clear from just examining the URL as to what version of the resource representation we are referring to. For us, this is a practical consideration which simplifies our customer’s interaction with our support team (which directly translates to $$ saved and customer satisfaction);
- In large scale, some performance benefits may be gained by parsing the start line of the HTTP request to perform backend routing rather than parsing HTTP headers;
In the next article, I’ll expand in more detail on the concepts of
module that will become standard vocabulary in the Nutanix REST API dictionary.