I used to read all these articles about the importance of making sure your API is RESTful and why versioning your API is so important and why you absolutely must keep your codebase under version control… and I used to think people were just being anal. I mean, who cares if I change my API in a backwards incompatible way? I’m the boss, I own and control it, and I can make sure the code that relies on it works, right? Well, for a time that will be true but one day you might find that the project you forgot to check into Git or the API you were meaning to get around to versioning is suddenly making you money and breaking backwards compatibility will cost you time and maybe money. I never thought these practices served any purpose other than making developers feel good about themselves for following best practices. Now I have a practical example from my own experience that will serve as a lesson for all my future projects. This is the story of how I came to understand why versioning your API is incredibly important.
Consumers, Clients, and Providers
Before we get into the examples, let’s define our terms. When we’re talking about API’s we’ve got API clients (also called consumers) and the providers. The clients are the apps that use the data provided by the API. The provider is the API itself.
Almost a few weeks back I launched my first iOS and Android app, MoonWeather. MoonWeather, the mobile app, is an API client. It feeds off of data from the MoonWeather API which I also built myself. It’s a simple Sinatra API built in a non-modular style. It did what it was supposed to and worked well. Then something funny happened. People started downloading and using the app. Great news, right? Well, not exactly. Now I had clients out there all relying on the same version of the API. If I wanted to add features to the mobile app then I needed to add features to the API as well. Some of the features and bug fixes required me to change the API in ways that required me to change the client. Do you see where the problems arise here?
Versions… oh, versions
Okay, let’s show some examples of this in practice. This is a real one from MoonWeather. Version 1 of the app makes a call to the API which returns 2 JSON objects – the weather and location information about the user’s current position. Once I got enough users using the app I began to come close to running up against the API limits set by one of the API providers I use to get some of my location data. At the same time I found a bug where sometimes the location provider would send ASCII characters in their response which my server would try to parse as UTF-8. This caused an internal server error when searching for locations outside the US. The solution to both of these issues was to remove the location information from the API and have the client request it directly from the API provider. This allowed my API to only focus on gathering weather information, solved the server error bug, and solved my API limit issue.
That’s all awesome. So what now? Just push the new API and client? No. That can’t work. It can’t work because you can’t expect all of your users to upgrade simulataneously. If I had just pushed an API and client update at the same time some users wouldn’t upgrade for a while so the old API calls needed to work while users of the new client needed their API calls to work as well. Even if users somehow magically did all upgrade the app at the exact same moment, Apple’s review process for the iOS App Store means that I can’t know when the update will be released so I couldn’t know when it would be safe to push the API changes.
That right there is exactly the kind of situation that warrants a versioned API. Unluckily for me I did not structure the API for easy versioning. Luckily for me it was a sinatra app that was so simple it wasn’t too hard to restructure it. So that’s what I had to do. I restructured the API so that any calls from the original batch of clients (up to version 1.1.2) will use the original API (I’m call it 0.1.1-beta). Now I’m finishing up testing version 2.2 of the mobile app. I already have the new API version live and running alongside the beta version, using the same codebase. Now when version 2 of the clients are released both the new and old versions of the app will still work. Maybe I’ll write a post on simple API versioning for Sinatra apps later.