API Versioning

Marcelo Cure
4 min readFeb 23, 2024

It’s been a while since the last time I posted here. I intend to start writing again.

On today’s post we’ll talk about API versioning.

Contract

Starting from the basics, what is a contract? Contract is the actual rules of a given endpoint agreed between server and client, or previously defined by the server.

On the body it includes:

  • Object’s structure
  • Field names
  • Datatypes
  • Even the sort order

Contract also includes:

  • Path
  • Path parameters
  • Query parameters required/non-required
  • Headers
  • HTTP response body, headers, status code

It means that whenever a request is sent to this endpoint, the API will, or should =], validate the contract.

Example:

Non breaking changes

There are contract changes that do not break the contract. Taking as example the API call above, if the response returns additional fields, it’s not a contract break because the consumer will continue to receive the same information it received before plus the additional fields. Another example is, the request body includes a new not required field, it’s not a contract break because it’s optional.

Contract Break

A contract break happens when you have an existing endpoint like the example given above and something changes that can break your consumers.

Let’s take the example above and make a breakable change: any POST to /v1/customers now requires a new field called birthCountry. It means that the customers will not send this new field and they will receive errors while trying to create new customers. Another example is a attribute name change, let’s say the field “name” was renamed to “fullName”, the result will be the same, the consumers will continue send “name” and will receive erros as well.

The same applies for GETs, PUTs and PATCHes.

It is a contract break! Oh my god, what to do?

Version your contracts

Before talking about versioning, we need to tell that companies evolve, business evolve, and its APIs have to evolve too, and it’s part of the game.

Whenever we have to make a change that break contracts, we need to version our endpoints.

We know that, to create a customer, we need to send the request below:

But now we need to add a new required field called birthCountry.

The first thing to think is: do not break your consumers, that’s why we create a new version and the old one will continue working for some time (we’ll talk a bit more about this ahead).

So we would have now an additional version, the famous v2 =]

Version management

For a matter of organization, code cleanup and business/API evolution, we know that both versions should co-live for some time.

Let’s imagine on our example that we have 4 consumers for the POST /v1/customers and we have just created the POST /v2/customers. Naturally we want the consumers to start using our new version, but it’s not always a change that will happen ASAP, different teams have different priorities let’s deal with it.

The team responsible for the Customer API must contact the teams responsible for the consumers and warn them that there is a new version, its importance, and establish a deadline for the consumers to migrate to the /v2/customers.

Also the Customer API team should have metrics to point out which consumers are still using the old version. That’s why it’s a good thing to know the consumers, I understand that it’s not always possible. It’s impossible for APIs like X API (past twitter) to know all the consumers and avoid them to have problems when an old version is removed.

After the deadline the new version will be removed and the codebase of the Customer API will be cleaned up to remove the old code.

Versioning strategies

On this post, the example I gave was /v1/customers, that’s just one way to version a contract, I’ll list here some ideas for that:

  • on the path: /v1/customers
  • on standard headers, example: Accept: application/json;version=1
  • on a custom header, example: x-api-version: 1
  • using query parameters: /customers?version=1

Personally I don’t like the idea of versioning on query parameters, but the other options are fine and widely used.

Be cautious

Having many versions implies in more code, more complexity, more bugs, bigger code base, slower builds …

Importance of API design

It’s important to properly design your API, it avoids having lots of versions and confusion with consumers =]

Here is a post I wrote some time ago about API design it’s worth the read.

I really hope I helped you to understand some things that are important to consider when versioning your APIs.

Feel free to comment here if you wanna discuss more about it.

--

--