Should an API use Semantic Versioning?

Recently I was talking with the Trebble team on a "X Space" they were hosting all about API versioning, and one topic came up which I wanted to delve into further: Semantic Versioning for API Versions.

Should an API use Semantic Versioning?

An article I wrote for Trebble, and the video, cover whether or not you should use API versioning for an API. Ignoring that larer topic, if you are using API versioning, how should those version numbers work?

If you're an experienced developer who's new to API development, it's natural to try and bring over concepts you've used elsewhere in the world of software. It's common to see people trying to use Semantic Versioning for API releases, like you might for an NPM package or some other software library.

For an API this would mean deploying and maintaining multiple versions of the API, all taking up server instances, which use up resources, costing money and creating carbon emissions:

  • https://example.com/api/1.0.0/*
  • https://example.com/api/1.0.1/*
  • https://example.com/api/1.0.2/*
  • https://example.com/api/1.1.0/*
  • https://example.com/api/2.0.0/*
  • https://example.com/api/2.1.1/*
  • https://example.com/api/2.1.2/*
  • https://example.com/api/2.1.3/*

Beyond costing money, what would be the point? If you've fixed a bug in 1.0.0, then you probably want API consumer to get that fix, without needing to communicate with everyone telling them to update the URLs in their code/config to the new 1.0.1 URL.

What about minor versions?

This gets folks thinking they should just use two version numbers, which in SemVer would be major and minor. Minor changes are meant to be "backwards compatible", meaning you can add new functionality without breaking anything already in use. If an API has a v1.1 it might add some new resources, or add new properties to a response.

  • https://example.com/api/1.0/trees
  • https://example.com/api/1.1/trees
  • https://example.com/api/1.1/units

Sticking with my current domain of fighting the climate/biodiversity crises, this is a change our API has recently seen. We've gone from tracking planted trees, to tracking various types of units, which could be meters of hedgerow, square meters of wildflower meadow, or square meters of peat bog re-wetted. If we were using major/minor versioning we'd have added units to v1.1 because adding things is backwards compatible, but we'd have kept trees the same because removing them in not backwards compatible.

Whilst at first it feels sensible to use this major/minor approach, it is equally as odd as the major/minor/patch approach discussed above. If an API has /1.0 and /1.1, but any code interacting with /1.1 will work the same as if it worked with /1.0, then... why bother maintaining those multiple instances? That /units resource could have been added to /1.0 and nothing would have broken for anyone.

Major Global URL Versioning

With minor and patch versions providing no value, taking them away leaves you with the most common approach in API versioning: major global versions.

  • https://example.com/api/1/
  • https://example.com/api/2/

Whether this approach should be used compared to something like API evolution is up-for-debate, but if you are going with URL versioning, please stick to a major version. Minor and patch versions are just noise.

More reading

Our friends over at Treblle recently posted a great primer on API Versioning, which makes a fantastic companion for this article. Add it to your reading list if this is something you're thinking about.