“Alexa, turn on the kitchen lights.”
I sat there in silence for a few seconds, waiting for the darkness around me to go away.
“Alexa, TURN ON the kitchen lights.”
A brief pause, and then the response, “I’m sorry, I can’t find a device named kitchen lights.”
Well that was wrong. I set up my kitchen lights to be voice controlled 3 years ago. I have turned them on and off multiple times every single day. I have used that command 1,000 times.
I try again - same response.
I open the Alexa app and look at the devices. Sure enough, kitchen lights was not listed as a device anymore. What was going on?
The lights were controlled via my SmartThings hub. Alexa would talk to SmartThings, then SmartThings would turn my kitchen lights on and off.
Turns out, SmartThings made a breaking change in their API, forcing me to reauthenticate with Alexa and add all of my devices again.
Frustrating, as you might imagine.
It was something I had no control over, and it broke an integration I set up years ago and have been happy with ever since. Needless to say, it left me feeling a little helpless and mad at SmartThings for making me go back and set everything up again.
This can happen to any of us. As web developers, we must be careful when we make updates to a live API. Consumers use those APIs for every use case under the sun, and if we make a breaking change, we can cause some serious frustration.
So let’s talk a bit about breaking changes.
Simply put, a breaking change is an update that fails to maintain backward compatibility. With API development, this could be from a variety of things:
As you can see, there are plenty of ways to make breaking changes to your API. There are plenty more ways I didn’t mention, too.
All this goes to say, when you’re maintaining an API in production, be intentional about every change you make.
Looking at the list above, you might be asking yourself, “so what can I do once my API is live?”
To be honest, your choices are limited. In fact, so limited that the only thing you can do is add optional fields.
If you must make a breaking change, like adding a new required field or grouping data in a different way, you will need to version your API. You can version a specific endpoint or you could add a new major version to your entire API.
But whatever you do, remember - you must continue supporting the old version!! At least until a deprecation date where you give your consumers an appropriate amount of time to prepare.
If you use the API feature in Postman, you already get semantic API versioning out-of-the-box. Postman will track all versions and schemas of your API for you, tracking specific monitors, mocks, and documentation related to it as well.
Of course, you are responsible for the actual implementation of the API - making sure you keep separate versions deployed, but the tracking and public facing pieces are handled for you.
Versioning your API can be done in multiple ways, but the two most common are:
When you update the url to include the version, you might go from something like this:
If you version a specific endpoint instead of the entire API, it might be:
If you want to pass in a version header, you must start including the header on all your endpoints. If the header is not passed in, default to the current version. If it is passed in, use that version.
Warning - This method is essentially a breaking change. If your consumers do nothing, they will automatically be upgraded to the new version.
Now that you are appropriately nervous, let’s discuss how to prevent breaking changes from sneaking their way into your API.
You can always hope that reviewers on pull requests will catch any breaking changes, but that is destined to fail. Humans make mistakes. Whether they’ve done it 1 time or 1,000, something will be forgotten and slip through the cracks. So we need automation.
I have created a Postman Template that will automatically check the current version of your API for breaking changes. The template is a collection intended to be run by Newman in your CI pipeline (you can also run it manually if you choose to do so).
The template uses the Postman API to load the current and last version of your API and compare the two. The comparison checks for all the things I listed at the beginning of this article: no new required fields, not removing optional fields, no changing data structure, no removing response codes, etc…
If any breaking changes are detected, test assertions fail, causing your pipeline to fail. This means your pipeline will not complete successfully if you have an accidental breaking change. Yay!
To get started with adding the breaking change detector in your CI pipeline, you first need to import the template into your workspace.
With the template imported as a collection, we can now go get the environment on GitHub. Simply download that file and import it as an environment in Postman.
Next, we need to create a Postman API key so we can dynamically load our spec via the breaking change detector collection.
To add the detector to the pipeline, we need to create a new step that will run
An example step using Bitbucket pipelines:
- step: detect-breaking-changes
name: Detecting Breaking Changes
- npm install -g newman
- newman run https://api.getpostman.com/collections/$BREAKING_CHANGE_COLLECTION_ID?apikey=$POSTMAN_API_KEY --environment https://api.getpostman.com/environments/$BREAKING_CHANGE_ENV_ID?apikey=$POSTMAN_API_KEY --env-var "env-apiKey=$POSTMAN_API_KEY" --env-var "env-workspaceId=$POSTMAN_WORKSPACE_ID"
In the step above, we are installing newman in the build container, then running it against our breaking change detector collection with our environment. We are also overriding environment variables
env-workspaceId to contain our api key and workspace.
The command above makes use of pipeline variables. We use variables so we can build reusable pipelines across multiple repositories, and so we can prevent storing sensitive information like API keys in source code.
The variables we use to run newman are:
With that, you are configured and ready to go! Now whenever your pipeline runs, the breaking change detector will compare the current version of the API spec with the previous and let you know if something is broken!
If you don’t want to go through the hassle of setting up a CI pipeline, or maybe think it might be a bit too intrusive, you always have the option to run it manually.
Simply configure the environment with the values from above, and you’re free to run the collection through the collection runner whenever you like! Tests will be generated dynamically as you build the spec, so no need to update anything in the collection itself.
You also have the option to become a watcher on an API. If your team is updating the API spec through the Postman UI, you can easily watch for changes and be notified whenever a change is made.
When a change is made (not by you), you will get an in-app notification saying a change was made. You will also get an email with a little more color.
The email will contain who made the change, what version was edited, and what changes were made. This gives you the ability to do your own audit and catch potential problems before they even make it to the build!
From here, the next thing to do is to try it out. Follow the instructions above and either bring it into your pipeline or start running it manually.
Preventing breaking changes is important, and it should absolutely be a part of your governance model when it comes to APIs. You don’t want to get into production and break the app for everyone by accident!
We’re in the early stages of getting strong API governance built-in to tools like Postman. So if you have improvements or ideas on the processes, share them! Drop a note on Twitter or write on the Postman community forum. We are there to make APIs better, stronger, and easier.
Good luck and have fun making great APIs!