Create Versions of your Api painlessly

Data

When you already have an app in production or a public API, you can't make changes to this API without a big cost. If you change the input or the output of a url, every client using your API has a chance to crash. The only solution you have would be to create a new version of your API.

Pass the version number

The first thing you have to do is to accept a version number from the clients. There are three ways to do it:

  1. Prefix all the url by the version number ([GET] /v2/users to get the user in the API v2)
  2. Use the Accept Header (ACCEPT: application/vnd.myapplication.version-2, application/json)
  3. Use a custom HTTP header (X-APP-VERSION: 2)

The first solution allows you to easily change the url name from a version to another. As one url will always return the same result, it is also more respectful of the REST standard. Nevertheless, it's often more complex to implement (you have more entry points in your application).

The second solution creates less entry points in your application. It is also retro-compatible if you forgot to handle versioning in your first version of your API.

I do not recommend the third solution which has the same advantages as the second one in a less standard way.

The Model

Often, the input and output of your API are similar to your database model. When you create a new version of your API, you have two options:

  1. Create two versions of your model
  2. Detach your outputs from your model

If you choose to create several versions of your model (like a user and an user_v2 table) you will have trouble keeping them in synced. A user must be able to sign up in an application using both the v1 API and the v2 one. You create duplication of your data.

The best thing to do is to be able to return v1 and v2 outputs from the same entity. The following diagram shows the architecture I recommend:

API versionning diagram

Every entity has an associated representation for each API version. The representation is simply another class for the same domain concept. The properties of this class are the ones exposed in the API.

We use transformers to make the link between the Model entity and your representation. If you have to change your model, just adapt your transformers without changing your representation and the API outputs won't change.

If you want to see an implementation of this architecture for symfony2, you can read my article on the subject.

New versions and API deprecation

It is quite painful to maintain a lot of versions of the same API for a while. At some point, you should be able to mark old versions as deprecated and delete them.

One way to do it, is to have a special endpoint with the list of available versions. The endpoint can return something like :

{
    "availableVersions": [4, 5],
    "deprecatedVersions": [3]
}

In this example, the versions 1 and 2 have been deleted and the version 3 is deprecated.

In the client, you should check the API version you use. If it is a deleted or deprecated version, you should show a blocking message to force an update.

You can also signal that a new version is available.