Versioning is essential if your API is likely to be used by API enterprise customers. Versioning allows us to potentially make breaking changes at some point in the future. Although we can believe, we’ll never make breaking changes that’s going to be incorrect. There’s always some sort of business or technical reason that we need to make a change.
Anticipating and providing a way of handling change is one of the central themes of REST. We need evolve our systems gracefully without breaking our already deployed clients.
One thing to keep in mind is that keeping backwards compatibility forever is difficult and like cost-prohibitive for most businesses. We need to ensure that our versioning supports advanced notification of depreciation, redirects, docs and etc.
Versioning if done carefully shouldn’t force everyone to move to the new API at the same time.
We need to version so that our clients won’t break every time we update the API. Not all changes should necessarily require our clients to update their api version.
When to use versioning
- versioning shouldn’t need to be done when we are adding new parameters to the response body.
- changing the data type of a request parameter or a response parameter will require a new version
- new required additions to the request body will require versioning
- removing anything from the response body
Breaking changes should always result in a version change. Keep in mind that some clients will need to deserialize your JSON or XML response to a custom class so even changing a data type could be a breaking change.
Version Naming Strategy
I like to follow semantic versioning as I find that relatively intuitive and believe it to be the industry standard.
A semantically versioned api would look something like this:
The Major version is used in the URI and points out there are breaking changes. Internally, a new version implies that we’re creating a new API and the version number is used to route to the correct host.
Minor and Patch Versions.
I usually use these only in change logs to talk about new functionality or a bug fix. They don’t normally end up in the URI or in http headers.
How to Version a REST API
There are no specific guidelines on how to version an API. There’s a few different ways of potentially versioning an API though whether it be through the URI or through header values.
Versioning in the URI
A common way to version is to add a version number in the URL. For example: https://api.example.com/v1/books/12
“v1” is the version number. If we needed to increase the version number due to breaking the changes the URI would then become: https://api.example.com/v2/books/12
|Easily implemented||Every breaking change is a new potential fork of the API|
|Client can easily cache results|
A lot of large well known tech companies use this approach like Facebook, Twitter, Airbnb and Salesforce.
Versioning through a Query String
I don’t see it very often, but there’s been a few APIs I’ve connected to in the past that use a version number in a query string.
For example: https://api.example.com/books/12?v=1
As the version increases, v increases.
I don’t personally like using the query string as it is more difficult to route requests to the proper version.
|Easily implemented on the client side||Redirecting on the server side can be difficult|
|Default versioning is very easily on the server||By default most caches ignore query string values|
Versioning through a Subdomain
The concept for versioning through a subdomain is that each major version of the API would get a new subdomain. For example, v1 would look like this: https://api-v1.example.com/books/12 and v2 would look like this: https://api-v2.example.com/books/12
I don’t mind this approach and think it could be pretty easy to set up in an API Gateway. The only challenging part is that you will need to potentially set up new subdomains and certificates every time you went out another major version.
|Very clear what API is being called||Higher set up time: new subdomain, having to use a wildcard cert|
|Caching is easily implemented|
I don’t see this very often and I think that’s because very few organizations have development also doing the operations or set up of domains, certificates, and etc.
Versioning through a Custom HTTP Header
A custom http header like “Accepted-Version” allows us to avoid changing URIs which then makes versioning done through headers. I’ve seen this done this way, although I prefer to use standard headers where possible like the “Accept” header.
|Relatively Easily implemented||Really a duplicate of using the existing Accept header.|
|Many different API Gateways can’t handle the versioning themselves.|
|Requires custom headers|
Versioning through the Accept HTTP Header
The Accept header allows us to keep a clean set of URI’s but it comes with the complexity of serving different versions of content somewhere else. The API controllers end up becoming responsible to figure out what version of a resource to send.
I find that the resulting come becomes really complex and challenging to follow. I don’t generally recommend using the Accept header.
Wrapping It Up
Versioning is one of the most critical parts of API design. It’s very difficult to update a public (or externally supported) api without versioning set up from the start. Content Negotiation is usually the hardest to initially implement because most libraries don’t support it out of the box.
The URI is usually where versioning ends up because it’s easiest to work through. I prefer to do it as part of the URI and not as part of the subdomain.
Also published on Medium.