brent777
brent777

Reputation: 3379

REST API versioning

I currently work on a Java based web application. Recently we created some REST endpoints using Spring. The reason for this was because we developed a hybrid mobile app that integrates with our main application via these end points.

The problem is that going forward we are not quite sure how to handle updates. If we update our API, e.g. we change the method signatures of the end point methods or we change the attributes on the DTOs that we return as JSON, then we would have an issue if our mobile users are running an out dated version of the mobile app.

What we want to implement is something that will force our users to update the app if it is out of date. I have seen a lot of mobile apps that do this. So we thought of having an API version for our REST API and then have the mobile app check if the version it is using is the same as the version being run by our server and if not, then force the user to do an update.

The problems we have are:

  1. We only have one version of our server running at any time. So how would we time our releases? What happens in the event that we release a new version of our API and our mobile app but the app store does not yet have the latest version publicly available. Then the user will be forced to do an update but the updated app is not yet available to them.

  2. How do we maintain the API version number? On the mobile app we can just configure that. But on the server it is not great to have to maintain a version number. The reason I say this is what if we make a change to a method signature or DTO, etc, and forget to update this version number manually before releasing? Surely there is a more automatic way to do this where some unique "API key" is generated based on the current definition of the API? We could then use this instead of an API version number.

Upvotes: 8

Views: 2656

Answers (2)

Brandon
Brandon

Reputation: 10058

There are a few things you can do.

  1. Architect API versioning in from the beginning. There are 2 common approaches I have seen for this with REST API's: putting a URL prefix like /v1, /v2, etc. before all REST resource end points or using the HTTP Accepts header to negotiate versions. There are religious wars on which one is right. It's your API. Do what you think is right.
  2. Abstract out business logic from API endpoint code within your source code. This way, you can have a v1 and v2 endpoint which re-use common code at a lower-level service layer. This is something you don't need to do from the get-go. You can wait until v2 of the API to start separating things out.
  3. Automated testing of each build against existing API versions (and whatever new version you are building, but regression testing is the key point I am making).
  4. Forcing app updates, or at least tracking usage by app version, can allow you to remove/cleanup any code supporting legacy versions.

I am working on a similar project, creating a new REST API for a new mobile app. I am partitioning the URL space by version, so https://api.blahblahblah/v1.0/resource.

For the moment, I have my business logic built right into the code that accepts the HTTP requests because there is no other use for such logic. However, when I need to make a new version, I will refactor the v1 API code to separate anything not v1-specific into a more re-usable module which can then be re-used.

Depending on how structurally different your versions are, you may need some redundancies to keep your API's separated. For example, maybe you need a general UserEntity object to represent information about a user from your database, but then need a UserV1Resource and UserV2Resource object for the separate versions with adapters or some other design pattern to mediate the different types which get serialized to JSON or XML.

By having automated API tests, I am free to do any of that refactoring as I need, separating as I go, knowing that the moment I break any backward compatibility, my tests will scream at me.

A nice benefit of the API only being consumed by our mobile app for the time being is that we only need to worry about compatibility with the supported app versions. If we can make sure our end users are updating their app regularly, we'll be able to remove older versions, which helps minimize our technical debt.

Upvotes: 3

Brian Kelly
Brian Kelly

Reputation: 19305

Sounds like you need to make backward-compatible updates to your API.

Since you're in control of the client code calling the API on the mobile side, just code your app to ignore new fields that appear in the JSON responses. That will make the app far less brittle and allow you to expand your objects at will. Make the most of HATEOAS and have your clients navigate the hyperlinks within your objects rather than hardcode them to your URL structure.

You should start to build a culture and process of compatibility testing with each server release, so that you can verify automatically that your older API clients (which of course will live forever on the phones of people who never update their apps) will still work with the update you're planning for your server. In Semantic Versioning, this is akin to making a minor version upgrade to your API.

If you believe you'll at some stage need to make a vastly incompatible API change that would break your older apps, then build in a "compatibility check" into your API clients from the beginning. Upon startup, they should check a simple API on the server to do a basic version handshake. If the server responds with a "we simply can't support your old client code anymore", then have your app error out with a message that tells the user to pull the latest version from the app store. But since that's a pretty nasty user experience, it's better to just build in sensible compatibility from the get-go.

Upvotes: 0

Related Questions