Avoid API Versioning Pitfalls with Spectral

Phil Sturgeon
by Phil Sturgeon on November 14, 2022 6 min read

This is one of our Public Style Guides, a part of our Style Guides rulebook series. If you want to subscribe to be notified of new guidelines, put your email in below.


Most APIs use some sort of API versioning unless you’re one of the bold few using API evolutions. There are so many different ways to handle versioning and some common pitfalls you can get stuck into, but if you point Spectral at your OpenAPI descriptions, it can help you avoid some of those problems.

The most common approach to versioning is URL versioning, like this:

  • https://api.example.com/v1/foo
  • https://example.com/api/v1/foo
  • https://example.com/api/1.0/foo

There are other ways to version APIs, too, of course, including global and resource-level versioning with a header, versions in the query string, all sorts, but the new Spectral URL versioning ruleset sticks to doing one thing well: giving advice about how to handle URL versioning. This is also available in the Stoplight Platform for those on Pro and Enterprise accounts.

Screenshot 2022-11-15 at 1.56.11 AM

Let’s take a quick tour through the rules to see how Spectral can keep all your API teams on track before they build and/or document their APIs all sideways.

Only Major API Versions

In the above list of URLs, you might have noticed https://example.com/api/1.0/foo, and this is something you almost certainly want to avoid.

Like it or not, Semantic Versioning is at the forefront of countless developers’ minds, and whenever 3 integers appear separated by dots, they’re going to assume your API is using SemVer. According to SemVer, new changes on a “minor version” should only be additional, so going from v1.0 and v1.1, there might be a few new endpoints, new properties, new links, and general changes that don’t break client interactions.

If a new version doesn’t have any breaking changes, why would you deploy it on a new URL? Doing that means a few things:

  1. API consumers will have to update URLs in code and deploy new versions.
  2. Any API consumer data with the old 1.0 URL will need to be updated to the 1.1 URL.
  3. You’ll need to host both API versions simultaneously, or
  4. You’ll need to set up redirects from one to the other which could break client interactions.

Deploying minor versions of APIs is a big old mess, but sometimes people will even pop a patch version in there, making URLs that look like this: https://example.com/api/1.0.1/foo. That whole list of unnecessary work above is now made even worse because that unnecessary work is being required for API consumers to get a bugfix…

If you’re going with URL versioning, sticking to major versions only is going to avoid a whole lot of unnecessary busywork for everyone involved, and this rule is here to help make sure everyone in your organization gets a reminder of that via a handy warning.

No Path Versioning

If you are using global API versioning in the URL, the whole API could change between versions, meaning there’s not a lot of benefit in trying to smush multiple APIs into a single OpenAPI description.

servers:
  - url: https://example.com/api
paths:
  /v1/foo:
  /v2/foo:

Who has seen this? At first, it feels like a good idea to keep all the descriptions of that one API and the multiple versions in a single OpenAPI description, but doing this leads to increased chances of accidentally leaking a change between v1 and v2 endpoints.

Conceptually, API v1 and API v2 are more like different APIs. They could have entirely different authentication, different data formats, different error formats, different naming conventions, or anything different. With all this potential difference, the benefit of keeping them all together is smaller, and it’s just a matter of time until somebody makes things a bit too DRY and refs to something they shouldn’t.

There’s also another concern. Resource-level versioning or method-level versioning; are two concepts talked about more in API Versioning Has No “Right Way.”

Resource-level versioning says a /v1/trees and a /v2/trees are totally different things but maybe /v1/species is still the latest and greatest species, and there is no v2. That’s a bit confusing, but method-level versioning is even more confusing: you might want to GET a v2 because it’s got the latest and best data, but there wasn’t a need for a new update method, so you’re PUTing to a v1 after running `convertV2ToV1($resource)`. From personal experience, this will blow up in your face in myriad ways for years.

Whether it’s a confusing use of OpenAPI or a confusing choice of versioning system in the API, this rule will help you out: if defined URL paths contain what look like API versions, it will suggest you put them in the server definition.

servers:
  - url: https://example.com/api/v1
paths:
  /foo:

Three birds, one stone.

One API Version Per Document

One last check here now that folks aren’t putting multiple versions in paths is to make sure the server’s array doesn’t also contain multiple versions, as that would lead to even more confusion as all paths would then be inherently shared.

Having multiple servers with a version in is fine if they’re the same version, which might happen if you’re describing two different environments.

servers:
  - url: 'https://api-dev.example.org/v1'
  - url: 'https://api.example.org/v1'

Having two different versions will trigger an error in Spectral.

servers:
  - url: 'https://api.example.org/v1'
  - url: 'https://api.example.org/v2'

Quick Start with Stoplight Platform:

Stoplight Platform comes with a public style guide set that can be enabled within your Stoplight workspace with a single click. The Versioning Style Guide is the latest addition to the list.

To use these rules:

  1. Go to your Stoplight workspace.
  2. Create a style guide project OR edit a project that has an API.
  3. SelectManage Style Guides.
  4. Enable Versioning from a list of public style guides.

    Screenshot 2022-11-15 at 3.01.38 AM

You can then:

  • Use the style guide as-is to automatically lint your API files

Summary

Versioning is a very controversial topic, and we could talk about it all day, but that’s what Twitter is for. This ruleset focuses on guiding people away from common pitfalls when using the most common type of API versioning: URL versioning with numbers. If you’re interested in helping make more rulesets that cover more types of versioning, please get in touch and share it with the Spectral Rulesets repo when you do.

Share this post

Stoplight to Join SmartBear!

As a part of SmartBear, we are excited to offer a world-class API solution for all developers' needs.

Learn More
The blog CTA goes here! If you don't need a CTA, make sure you turn the "Show CTA Module" option off.

Take a listen to The API Intersection.

Hear from industry experts about how to use APIs and save time, save money, and grow your business.

Listen Now