The importance of being versioned

If you write or use a public web service, please read this post carefully. I’m shocked and saddened at just how poorly many of these APIs are designed. I’m not necessarily talking about the choice of REST or not, or XML vs. JSON, as these are somewhat matters of preference and usage patterns. I’m talking about whether or not the API is versioned.

What is a versioned API?

A versioned API is one where you can select the version that your site consumes. As a very simple example, consider YUI. The most recent version is YUI 3.3.0 and can be included in your page using the following code snippet:

<script src="http://yui.yahooapis.com/3.3.0/build/yui/yui-min.js"></script>

Note the embedding of the version in the URL – this is how YUI handles API versioning. That means you can choose to use an earlier version, say YUI 3.1.0 by using this code instead:

<script src="http://yui.yahooapis.com/3.1.0/build/yui/yui-min.js"></script>

Many web services use a similar methodology, either providing the version number in the URL or as a parameter to the API.

Why versioned APIs are important

A versioned API is a contract between the producer of the API and its consumers saying, “I guarantee that this API will continue to work this way for the foreseeable future.” Put simply, if api(2, 3) returns 5 now, it will always return 5. And that’s the number 5, not a string “5″, or a JSON object { value: 5 }.  Of course, not all APIs are this simple.

Realistically, APIs need to change. Bugs need to be fixed, security holes closed, out-of-date schemas updated, and so on. You absolutely cannot expect an API to never change. It’s how you manage these changes that makes all the difference to consumers. Versioned APIs provide the ability to make breaking changes without breaking already-existing implementations.

Consider an API that is called by your site to embed a list of articles from a RSS feed. When you test, the API returns HTML as an ordered list with a class name of “rss-list”. You write your CSS to style the list appropriately. Your integration server is setup and verified by your QA team and the site is pushed live. The next day, the layout in production is completely broken. What happened? The API was changed to return JSON instead of HTML, as the API author believed it was inappropriate to force markup on the API consumers. While that may be a rational API design decision (though arguably one that should have been made early on), it’s irresponsible to make such a dramatic change to an API that others are using in production. Congratulations, you just broke the Internet.

A versioned API allows API producers to make those changes whenever you want. Will the change break code already in use? Just change the version. Whether it’s a minor point release or a major point release, just introducing the new version allows the API to continue to evolve while not breaking existing implementations. You can then notify the API consumers that there is a new version available and they can schedule an upgrade to use the new API version. The API consumers then can go through their normal integration and testing cycle to ensure that what goes out into production is fully functional.

Managing versions

There are a fair amount of decisions that have to be made when providing a versioned API. The most important decision is how to determine when the version should change. To be clear, not all API changes require a version change. Here’s the key determinant for a new version: are you changing the functionality in such a way that breaks current implementations? If the answer is yes, then it’s time for a new version; if no, then a new version isn’t necessary.

For example, consider an API that fetches article text. This API is experiencing problems returning data so that 50% of the time an empty string is returned. It’s unlikely that the API consumers are relying on this behavior so improving the rate at which actual article contents are returned doesn’t require a version change.

Schema changes can be tricky, both for input parameters and response formats. Adding additional optional parameters may not require a version change. The same can be said for adding additional fields in the response format. If you add a new required input parameter or change the name of a field in the response format, then a new version is required.

Bug fixes may or may not require a version change based on the scope of the change. Feature changes almost always require a version change – this includes adding new features and removing or altering existing features. To repeat: the key determinant is if the change you’re making breaks current implementations.

Supporting past versions

Just because your API is versioned doesn’t mean you need to continue to support all versions ever created. The correct rules for managing versions depend largely on the API itself, how frequently the API changes, and for how long you want to support old versions. The rules for JavaScript APIs are different than for web service APIs. There are, however, some general guidelines that you can start with:

  • Keep track of your API consumers. You may want to require an API key for use and tie that to a verified email address.
  • Plan to maintain at least two previous versions of the API.
  • The API should be backwards compatible for at least one version. That means parts of the API can be deprecated immediately but shouldn’t be removed immediately.
  • Each previous version should be supported (still available, but not under active development) for a minimum of six months. This gives consumers enough time to upgrade.
  • When a new version is released, notify the consumers (via email if you have an API key) and inform them of the timeframe for upgrade. The timeframe must be in months – many companies plan at least a couple months ahead of time.
  • Monitor usage of older versions. When you get within one month of end-of-life for a version, notify those consumers that are still using that version to give them fair warning. Do the same two weeks later.

Keeping API consumers informed of changes to the API is the most important aspect of these guidelines. No one likes it when their site worked yesterday and doesn’t work today – especially when they didn’t make any changes.

You’ll note that not all APIs have API keys, such as JavaScript libraries. Whether or not you use one is entirely dependent on whether or not you want to track API usage by consumers. If there’s no advantage to doing so, then you may not use API keys – you’ll just need to find some way to communicate with consumers about version changes.

Conclusion

The example I used earlier was for YUI, but this article also applies to any web services you may consume or produce. If you’re providing a public-facing API, please ensure that it’s versioned. If you’re considering using a public-facing API, inoculate yourself from random and unexpected errors by using only versioned APIs. There are too many companies that still insist on providing unversioned APIs for public consumption. These APIs put a tremendous burden on development and testing teams that is unfair and prevents their sites from being as reliable as possible. Give them that feedback – you’ll be doing yourself and all other API consumers a great service.

Comments

  1. Mike

    You've entered into an on-going debate, positioning your opinion as fact, and you haven't added much.

    In distributed applications in which your application (or API if you prefer) has, or hopes to have, many clients - one could argue the objective as a provider should always be to reduce the coupling of your clients. The very act of versioning is a big indicator that you are inviting your clients to couple tightly to your implementation at a given point in time.. this means that as you scale, and as your application changes over time your costs will balloon. That is a Bad Thing, and suggests that Versioning might be one of the worst things you could do for the evolution of your application and, by deduction, your clients.

  2. Kevin Hakanson

    Good article. If I were add one item, it would be to make sure you have test coverage for both versions. I have seen developers "update" their tests for the new version instead of making new tests. The update means the old version has lost its test and no longer has coverage. New tests leaves both versions with test coverage.

  3. Alex

    Versioning and keeping track of new features is very hard on JavaScript.

    While working on diagramo to bring it to life there are a few aspect I think are annoying:

    1. As the whole project is an experiment about HTML5 there are tons of new features and code changes that ARE necessary to make application work.

    2. The code is made out of several libraries and each library - even if I try to keep them as loose coupled as I can - refers sometimes to other libraries....and each one has its "own" version.
    So beside keeping all in synch it's hard to make a "general" version of whole application.

    I remember that Perl (I might be wrong about that... ancient times) has a feature that allows you to require a certain library version. That might be interesting to have...maybe a dynamic loader....

    Anyway your points are true but are more an observation of the problem than a solution - ok a partial solution.

    Do you know anything more about this...like a concrete example of how to maintain a bunch of JavaScript libraries?

  4. Kyle Simpson

    Nice post, great points.

    One point to mention... in this post, you seem to focus on the programmatic side of the API (like the versioned YUI lib). And, I assume also that you mean any "sdk" libs that one downloads to interact with a web-service, such as the GoogleMaps lib.

    But the other side is I think also important... the URL's of a web service calls themselves should also be versioned. Not everyone consumes a web service via your provided sdk. Sometimes they are hitting the web service (REST, etc) URL directly. Consider Twitter's API, for instance.

    The version numbering in the web-service URL calls is important because it not only tells the web server what incoming data format rules to expect from what you send in, but also it tells the server what response format you as the caller expect in return.

    Not disagreeing with your post... I think you probably meant to say this, too. Just was pointing it out explicitly, as I think it's quite important along with what you've presented.

  5. leonxki

    Valid points and a good read. Thanks for examples too.

  6. Marcos Caceres

    Versioning APIs is a terrible idea. You should design your APIs to be versionless and always backwards compatible. Putting versioning into URIs is even worst, as they get spread all over the web. Then you end up having to maintain all sorts of versions.

  7. Peritus

    I think the proper way to version your REST API is via a custom content-type (always a good idea):

    So, a request with a client understanding v1 of your api can do requests like this

    GET /list
    Accept: application/vnd.yourcompany1+json

    and the server knows which version of the api it should use. The same is true for POST requests (where the client can specify how the server should handle the data he is sending.

    Server and client can use content type negotiation to figure out how they want to communicate, you can announce new versions of your api, your cool URIs don't change, etc.

    Reminds me of the old days when desktop software like MS Excel versioned their file formats ..

  8. Nicholas C. Zakas

    @Mike - I'm not sure why you'd say I'm positioning my opinion as fact, this entire blog is my opinion. The disclaimer even specifically mentions that. I also have on interest in debating - this is my opinion and one that I've found to be extremely important in my job.

    I've never been upset that an API was versioned. You can use a single version for a long time if you can continue to make non-breaking changes (YQL's API has been v1 forever), but why limit yourself by not giving yourself an option? All applications are tightly-coupled to the external APIs that they call, so while you can try to not break them, I can't see a scenario where it would be better not to have the option.

    @Marcos - I've seen major sites go down because they used an external API that claimed to be versionless. In an ideal world, all APIs are backwards compatible forever. In the real world, this never happens. Things have to change, and versions allow you to do that without breaking everyone's application.

  9. Luke Shepard

    I work on the Facebook JavaScript SDK: github.com/facebook/connect-js

    For a standalone client library (such as YUI or Jquery), versioning makes sense, but it can make less sense if the Javascript library is tightly coupled with a server-based API and product that changes frequently. Since the server and client are updated independently, the test matrix can explode, and the maintenance of outdated versions is a major drag on new innovation.

    I have found that for us, a lightweight, unversioned client library lets the server do all the heavy lifting -- that way we can guarantee that all apps have consistent, up-to-date behavior without any code changes required for the developers. For non-backwards-compatible changes, we give developers a period of time (usually 2-3 months) to flip the behavior in their developer settings.

  10. Nicholas C. Zakas

    @Luke - I think your case is a good example of when versioning would benefit everyone. I really don't like the idea of a third-party being able to inject code into my site without my knowing it - that's exactly how bugs happen. I like to know exactly what's on my site now is exactly what was on it when I last tested.

    Honestly, I don't buy the "drag on innovation" argument at all. This is about managing quality and process. If your test matrix is getting too big, that's actually a sign that you should slow down a bit and rationalize the changes you're making. This is where a lot of errors creep in that are unnecessary and avoidable.

  11. Hari

    Versioning has definitly got it's benifits, but I would not recommend this for many cases.

    I would always want my third party reference library to use new and optimized code if it does same job... Otherwise it will be a head ache for me to watch for new release of APIs and keep updating my app..

Understanding JavaScript Promises E-book Cover

Demystify JavaScript promises with the e-book that explains not just concepts, but also real-world uses of promises.

Download the Free E-book!

The community edition of Understanding JavaScript Promises is a free download that arrives in minutes.