3

API Versioning Do’s and Don’ts

 2 years ago
source link: https://blog.bitsrc.io/api-versioning-dos-and-don-ts-4bd9db073f2a
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.
neoserver,ios ssh client

API Versioning Do’s and Don’ts

It’s never too soon to get started crafting your versioning strategy

Photo by Tengyart on Unsplash

Often when developing our APIs, we tend to ignore versioning because we’re literally building the first-ever version of our service. We can worry about versioning in the future, right?

Wrong.

Four months down the road we realize we need a new version of our API and suddenly a million questions pop up in our mind about the user experience, the breaking changes, the time to update and we realize just then that by ignoring the problem, in the beginning, we had just shoot ourselves in the foot, we just didn’t know it yet.

So let’s take a look at some bad and good practices when it comes to thinking and planning around the versioning strategy for your next API, so you can keep the other foot from being shot.

Versioning strategy

The whole idea of this article is that you need to have a way to organize the way you version your API. The better laid out your strategy is, the faster you’ll be able to grow and extend your API without affecting your users.

What is a versioning strategy? Essentially is a set of standards that you’ll use whenever you want to specify a new version of your API. Standards, by definition, are well documented, always follow a set of logical rules and if there are exceptions, they are clearly documented as well. The standard might include things like:

  • The logic behind the numbering system you’re using. Because after all the version number is supposed to mean something, otherwise what’s the point of using it?
  • The release schedule if there is one.
  • How to deal with multiple versions and what happens during a big update.
  • Default versions to use, deprecated versions to stop using, etc.

Really, the more you add the better it’ll be for your users.

So a big no-no would be to version your API however you see fit.

In practice, this means you’re:

  1. Arbitrarily choosing version numbers depending on how you feel that day. This is per se not a terrible thing, however, it does make it a lot harder for users to understand which version they’d like to use solely based on the number.
  2. You may not even be thinking about how the breaking changes you’re introducing will affect active users of your API. This is major and can hinder API adoption greatly because it essentially renders it unstable in the eyes of the client.
  3. You do not have a release schedule/way for your users to understand if improvements are coming soon. This renders the API obsolete the moment they see the need for improvements but can’t really tell if they’re coming or not.

What can you do to avoid all these problems and perceptions issues (because after all you might be working on the best API in the world and no one would realize that given the current lack of versioning strategy)?

Have a solid, well defined, and documented strategy

I don’t think that given the previous point, this will be a shocker. But just to make sure the point gets across: define a versioning strategy, publish it somewhere and make sure you stick to it.

What am I talking about here? Things like:

  • Defining what versioning scheme you’re using. This will give a hint to your users about what each new version implies. For example you can go with SemVer which would let your users know that if you go from 1.2 to 1.3 you’re just adding some non-breaking improvements, but if you go from 1.2 to 2.0, then something is probably going to break. Or you can follow Ubuntu’s versioning scheme which indicates the date of the release, so 21.01 would mean you released that version on January 2021. You’re adding value to your users by telling them exactly how old that version is. It doesn’t really matter what scheme you use, as long as you use one and document it clearly.
  • Letting your users know what happens to old versions after every new release. Are they deprecated? No longer accessible? Maybe kept accessible for a while? I personally have my own preference and I’ll share it with you down below, but consider being open about this and having it clearly documented somewhere.
  • Giving your users a high-level roadmap of what’s coming. It doesn’t have to be a fixed timetable where you commit to a specific number of improvements by a date. Just let them know what your plans are, by what version you might release each new feature and keep it updated. That way they’ll know you’re working on something new and they’ll know when to, roughly, expect it.

The point of the strategy is to give users and client app developers a standard way of knowing how to interact with your API and its different versions. Effectively stabilizing the development in the eyes of your users.

One version to rule them all

Versioning is fun until you have to decide what to do with older versions when a new one comes along.

Of course, this is only important if you actually have someone using your older versions, but let’s assume that’s the case here.

A big no-no in my book: only keep the latest version available online

Do you really hate your users that much?

Only having a single version available might seem like a good idea, because your clients will always have the latest version and every bug fix and new feature will automatically be available to them. Amazing!

Not so much.

Because the other thing that you can do when updating the API is releasing breaking changes. That’s completely valid, sometimes to move forward you have to break some egg you know? — that’s how the saying goes, isn’t it? — . The point here is that a new release might be as terrible as having a lot of crashing bugs. In the eyes of your clients, you’re releasing a very unstable product.

That’s not what we want.

Keep multiple versions in parallel

What can you do instead? With a well-defined versioning strategy, when releasing a non-backwards compatible version, you can keep the existing one and the new one working in parallel for a pre-defined window of time.

While that happens, you can notify your clients about the changes, and the deadline for them to update, if they so wish to do, before you’ll deprecate the older version.

And on top of that, if you’re following a versioning scheme like SemVer, you can automatically deploy minor and patch updates, without fearing issues with your client, and only leave major changes to be released through this process. That way clients only need to worry about specifying the major version of your API , instead of the full one (i.e they can say that want to use version 1 instead of 1.2.5 or 1.5.2).

Mind you, you don’t have to keep every single major version online forever, if you’re not releasing major versions every week, as long as you keep the last 2 versions online (i.e the new one and the previous one) it’ll be enough. Between then and the next major release, you need to make sure that you have very few users using the old — soon to be deprecated — version.

Documentation is for suckers

The documentation of an API will determine how much adoption it’ll get from its users. The better it is, the simple it’ll be for them to use it, you’re lowering the learning curve, and that’s something every user loves.

Big don’t: Assuming you don’t need to document obvious behavior

So a big no-no when it comes to versioning is assuming it’s obvious to everyone, and either you barely mention it in your documentation, or you avoid it completely.

Do not leave anything to the imagination of your users, for any aspect of your product, but especially not for one that dictates how they interact with it.

If given the choice, they might think it’ll be safer to lock their client into a specific version and forget about it. However, what happens if you decide to deprecate that version?

Or perhaps they think “new version” means “better version” — I mean, who wouldn’t? — so they keep always using the latest version. When are you going to tell them you’re breaking half of their client with your latest update?

Do: clearly document your strategy around versioning

The best practice here would be to have a dedicated section of your documentation where you clearly outline the versioning scheme used, what happens after each new release and cover how each type of release affects the existing clients. That last part is crucial because you want your users to clearly understand how they’ll be affected by a new version.

A fantastic practice would also include a release log after every new version bump. Even if it’s just a minor release, it should be a big deal for you — which in turn shows your users you care about them — and it should have a dedicated section within the release history.

Check out Shopify’s release docs as an example:

1*-XkbPYtU9X1jbiPgl-olZA.jpeg?q=20
api-versioning-dos-and-don-ts-4bd9db073f2a
Example of a nice API documentation

You can see several things in that screenshot:

  1. They follow a time-based versioning scheme.
  2. They Document every new version’s release individually and in detail.
  3. They even have a “developer previews” version, which is probably updated often with the latest new changes.

If you click on any of them, you’ll notice the level of detail, showing you things like:

  • Release date, so you know how exactly how old this version is.
  • The deprecation date, or how they put it: the date when this version is no longer going to be supported. This is major, as a client of this version, you now know exactly when you can no longer use it.
  • What’s new? The list of updates.
  • Breaking changes. Yes, they have a dedicated version for everything that will break your client application if you switch to this new version. That is what I call a user-centric approach.

Think about your users, not about how much documentation you need to write. I’ll leave it at that.

Standandars, schmandars

Who needs standards when you can define your own way of specifying things like what version your client wants to interact with, right?

If you’re keeping multiple versions of your API alive at any given point, you’ll have to provide your users with a way of telling you that, and the way you do so will also tell a lot about how much you care — or don’t care — about them.

Big don’t: come up with a very unique way of doing it

Perhaps you think that this whole versioning thing is not really a standard within your communication protocol so you’ve decided to come up with a unique way of specifying the version of your API.

Or maybe, you just didn’t take the time to research your actual communication protocol to find out how many different, standard, ways of doing it are there.

Whatever the case may be, forcing your clients to follow your non-standard ways will make their libraries obsolete. Remember, they’re most likely using libraries that deal with your communication protocol so they don’t have to re-invent the wheel. However, those libraries will usually (like 99% of the time) assume both client and server will follow the standards for the channel.

So if you’re using HTTP — which, let’s face it, it’s probably the channel 99,9% of you are using — for example, the library you’ll use won’t take into account things outside either the headers, the URL or the query parameters, to specify the version.

If you think you have a nifty new idea, consider the effect it’ll have on your clients. In fact, what about your API’s adoption rates? The harder you make it for your users, the fewer of them will actually want to use your service.

Make it easy for them to tell you the version they want to use

It’s that simple.

The easier you make it, the happier your clients will be. And you want them to be happy, remember that.

What options are there? Again, sticking to HTTP which is the channel I’m assuming you’re using here:

  • Header as part of the request. But not any header, HTTP has a thing called content negotiation which allows you to specify the type of representation that your client accepts of the resource requested. So through the Accept header, you can specify things like the mime type of the response as well as the version of it. That way you can have the same set of endpoints but through this header you specify the version of it. If you’re building a truly RESTful API, this is probably the best way to tackle versioning. The drawback of this approach, is that you either need to have a reverse proxy or some kind of gateway redirecting the request to the correct instance of your API based on this header, or you have to have that redirect logic inside your own API (essentially having all versions of the service living within the same product).
  • The version inside the URL. This implies having URLs such as /api/v1/your-endpoint-here . So if you now want to move on to version 2, just change it to /api/v2/your-endpoint-here . That’s a valid option, many use it. The problem with it? You’re technically coupling the unique resource identifier (i.e the ID of the resource you want to interact with) with the representation of the resource. For instance, consider the following request: GET /api/v1/images/family-photo.jpg and now GET /api/v2/images/family-photo.jpg . To HTTP, and thus at least to a truly RESTful API, those are two completely different resources, however, in practice, they’re most likely the same picture. It’s just a matter of you having updated the version of the API and now changing their ID. By definition the URI/URL of a resource should never change over time, so you’re breaking a standard. Mind you, if you’re not going for REST this might not be a problem for you, but keep it in the back of your head, just in case.
  • Specify the version as part of the query parameters. If you want to keep the version in the URL but avoid the above problem, try to shift it into the query params instead. So instead of doing /api/v1/images/family-photo.jpg you can say /api/images/family-photo.jpg?v=1 . You’re now using the params (which are not part of the unique ID) to do content negotiation. If you don’t have that many parameters at any given time, this might be a great solution. However, if you’re already using lots of them on all your endpoints, this will only add more noise to the full URL. This one has the same drawback as the first option: you need to figure out how to route the request to the right version. It’s not a big drawback, since there are multiple ways of doing so, but it’s still something you need to think about.

Those are the 3 most common ways of specifying the version of an API in the request. If you think you need something different, think again. Your users will thank you.

There you go, API versioning is no joke, you need to pay as much attention to it as you do to any other aspect of its development. And as such, you should consider having a strategy for it from the start. Even if you’re not considering having a new version of it for the next year, starting with a set plan will help you plan everything else around it instead of making it up as you go.

Finally, think about your users and about your API adoption when defining the versioning strategy, it’ll directly affect them — and in a bad way if you don’t do it properly.

Build with independent components, for speed and scale

Instead of building monolithic apps, build independent components first and compose them into features and applications. It makes development faster and helps teams build more consistent and scalable applications.

OSS Tools like Bit offer a great developer experience for building independent components and composing applications. Many teams start by building their Design Systems or Micro Frontends, through independent components.
Give it a try →


About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK