Managing Change Behind the Scenes with Continuous Regression Testing for a Seamless Customer Experience
Updating APIs can be a tricky business. Whenever you modify an API, even if it’s a minuscule change to the code, you run the risk of breaking some existing functionality in an unintended way. So even if you’re fixing a minor bug, you want to make sure other working components in the API are left unharmed. Otherwise, you can cause issues in your customer’s integrations—and when that happens, you hear about it.
When introducing breaking changes to an API, you want your customers to keep the version they already have and update when they are ready—so they can test the changes in their own systems before releasing any changes downstream to their users. This is why making sure your API versioning doesn’t break is so critical. We have two systems in place for that: point-in-time API versioning coupled with API monitoring from Runscope. Monitoring our APIs with regression tests is critical to making sure that our API versioning processes are effective and deliver value to us and the end-user.
We consider ourselves an API-first company, which means that our product and the way we interface with customers is entirely by APIs. There’s an expectation that APIs will be online 24/7. If a customer uses Clearbit for a product integration and our APIs go down or something breaks, then that can trickle down and cause issues in the customer’s system—and that’s not good for anyone’s business. So, more important than the way that we version and improve on our APIs is the way that we ensure that they’re performing optimally, and at all times. For that, Runscope is a vital component to our business.
Three Versions of API Versioning
Basically, you have three ways to version an API:
The first (and most common) is to include the version in the request URL — for example, v1, v2, and so on — and route different API versions to different endpoints. This works well for occasional updates, but quickly gets unruly if you have a lot of API changes.
The second approach, which I’ve seen GitHub successfully using, is to send the version in the header of the request. This approach (similar to url versioning) is probably best for APIs that only introduce breaking changes once in a great while.
The third approach, which I’m not sure if Stripe invented, but they certainly made it popular, is what we call point-in-time versioning. How it works is, the first time a user makes a request to the API, that point-in-time (timestamp) gets saved alongside the account data and becomes their version until they choose to manually bump it to the current version.
With this approach, when a user calls an API for the first time, they don’t have to worry about versioning. They make their first API request, and we record the version they are using automatically. Now, every time a user calls an API, that API version is locked.
Point-in-Time Versioning: Not a Numbers Game Anymore
The point-in-time method is slightly more complex, but it has advantages. For instance, at Clearbit, it allows us to make adjustments within our codebase without having to create create new endpoints within our system. It also allows us to easily see which API versions our customers are using. Since we’re anticipating quite a few changes to our APIs in the future as we improve them, this approach works well for us.
This approach also allows us to do some interesting things in our API Docs and Dashboard (below). We can look at the current version and compare that to the customer’s time-stamp. Based on that comparison, we can let the customer know they are not on the current version and, because we keep a detailed change log, spell out exactly what changes were made since their point-in-time version.
Someone once asked, how many versions of our API do we have? We don’t really think about versions in terms of numbers anymore. We think about them in terms of a point in time. This way if we ever have a breaking change, we can simply bump the timestamp on the current API to the time of change.
The key to all this of course is managing change on the backend so that API versioning is seamless for our customers. Basically, we need assurance that our versioning doesn’t break and that we can maintain this style without a lot of complexity.
Managing Change and Complexity with Runscope
By running a schedule of regression tests against our API endpoints, we’re able to support tons of API versions transparently. It’s easy for us to build and update tests and add custom headers and versioning so that there are no unknowns.
With dozens of API versions it’s important that we continually test their accuracy. We use Runscope for regression testing each of the versions. Runscope lets us test every point-in-time version we support and efficiently push out new versions when needed. We also know that we haven’t broken a legacy version that a certain percentage of customers are still using.
Plus, we integrate test failure alerts into Slack so we can triage API issues as they happen, and hopefully before they reach customers. Runscope covers all the bases for us as far as API monitoring goes.
As a developer, I typically don’t hear much until things go badly, so the radio silence on point-in-time versioning is kind of awesome. With Runscope, we can build tests, run them and then basically forget about it, because the less we hear from Runscope, the better. It means things are working as expected.