Third Party Developer Blog

Feb
1

Breaking changes and you - How to use alt-routes to enhance your sanity

CCP Bartender | 2017-02-01 14:19

Afternoon developers!

We've mentioned it before, but I'd like to give everyone a clear best-practices guide to how to use alt-routes in ESI to maintain application stability against a constantly evolving API.

Schedule of breaking changes

Before I get into that though, we previously said we'd be updating a forum thread with all planned breaking changes to ESI. That's turned out to be a bad solution to letting you all know when we're planning to change stuff. It's hard for you to read at a glance, and it's totally outside the tools we use day-to-day to develop ESI.

We've moved this information to the ESI deployment timeline, here: https://github.com/ccpgames/esi-issues/projects/2.

The timeline shows the deployment of totally new routes, but it also shows the deployment of routes that are going to have breaking changes. Consider the following screenshot:

We can see that on the 24th of January, the following happened:

  1. The /dev/characters/{character_id}/ route was bumped to v4. This indicates a breaking change on this route.
  2. /latest/wars stayed on v1, but we're making a breaking change to the spec.[1]
  3. /latest/universe/races was bumped to v1. Since v0's are not a thing, that means this was a newly created endpoint.

In general, you should know what versions of what routes you are using, and keep an eye on this page so you can see if those routes are going to be altered.

The importance of alt-routes

I've mentioned /v1 here, but let me expand, because this is important.

If you look at the top of the ESI UI, you will see three buttons: "legacy", "latest" and "dev". When you click on one, it will show you a list of endpoints that are available on that route. For example, you can make a curl request to https://esi.tech.ccp.is/latest/characters/95465499/, and get data about my marvelous self. Notice the "latest" in the middle of the URL.

You can also make requests to https://esi.tech.ccp.is/dev/characters/95465499/ (dev) and https://esi.tech.ccp.is/legacy/characters/95465499/ (legacy). These three routes may or may not return different data. Team Tech Co is supporting exactly three versions of a route at any one time:

  1. /dev (where we may test changes with the community before promoting them, if appropriate. There is no stability here, we'll break this one without hesitation.)
  2. /latest (the one you should be using)
  3. /legacy (the previous version of latest, for you to use until you can update your app back to current latest)

These three routes (legacy, latest, dev) are convenience labels to help you understand what is "current" at any given time. You should not be using them in your source code, as you will see in a minute.

When Tech Co promotes a change, we take whatever is in /legacy and throw it away. We take whatever was in /latest, and put it in /legacy, and put /dev in /latest. However, there's a problem here. If you're calling the /latest route in your app and we promote a breaking change, the /latest route will change underneath you, and your app will break. The legacy route still has the version you currently rely on, but your app is broken anyway. Sadface.

 

This is why you should be using versioned alt-routes. if you take a look at the current latest of /characters/{character_id}, you will see at the top a set of alternate routes: 

As you can see from the screenshot above, the current alt-routes are /v4 and /dev. These routes are aliases for /latest. This aliasing goes multiple directions. You can infer that /latest and /dev are identical at the moment, because /dev is an alt-route of /latest. /latest is also an alt-route of /dev, and behind the scenes all three are being directed to the same block of code.

However, more interesting is /v4. If you make a request to /v4, you will get the same as /latest. When we next promote the /characters/{character_id} route, we will move /v4 to be an alias of legacy. This means when we promote a breaking change your app will not break if you are using /v4. Instead, you will be smoothly transitioned into /legacy.

Once an alt-route is only available on /legacy (or if you call /legacy directly), your app will start receiving "warning" headers with every payload, even on 401 unauthorized errors. If your app is running through a CI system, one of your tests should be "blindly call every route I use and see if I get a warning header in the return". This will tell you if any of the routes you are using have been moved to legacy, so you can update your app back to latest.

So, to recap, to avoid having your app suddenly break when we push breaking changes to endpoints:

  1. Use the versioned alt-routes for everything.
  2. Never use the convenience label routes in your source code.
  3. Have some kind of test you can run that will aggregate and call all the routes your app uses, and tell you if it gets warning headers.
  4. Keep an eye on the deployment timeline!

And of course, the ever present 5:

If you want to keep up to date with ESI development or ask interesting questions, the best place to do it is in the #esi and #devfleet channels of the tweetfleet slack. You can request a tweetfleet slack login here.

 

I hope that explains a few things!

Bartender out~~


[1] This is complex, make sure you've read the rest of the blog before you come back to this. The code backing the /v1 route of wars was causing performance problem with the TQ cluster, so we chose to change the endpoint without bumping the version. This bypasses all the best practice stuff I just finished telling you, and risks breaking peoples apps. Because the stability and performance of Tranquility trumps other concerns, we chose to take that risk here. We couldn't afford to have people continuing to use the broken code, so we couldn't move it to legacy. Tricky problems with no good solution like this are exactly why it's important for you to keep an eye on the schedule and idle in the #ESI if you're running anything mission critical. This is not SOP; we only do stuff like this if we're backed into a corner.

back