Deactivating an API, One Step at a Time
How do you make sure all consumers stop using an API so you can safely deactivate it?
There are times when you have to stop serving an API. It might be that you want to replace it with a new, more capable version, or the features the API was providing no longer make sense. Whatever the reasons, what’s important is that no one depends on the API you’re about to kill. Otherwise, the consequences can be unpredictable.
This article is brought to you with the help of our supporter: Speakeasy.
Speakeasy provides you with the tools to craft truly developer-friendly integration experiences for your APIs: idiomatic, strongly typed, lightweight & customizable SDKs in 8+ languages, Terraform providers & always-in-sync docs. Increase API user adoption with friction-free integrations.
Not long ago I was involved in decommissioning an API that had been running for a long time. It had too many consumers. They were integrating it with numerous features across Web and mobile apps, and even using it to extend other APIs. Unfortunately, it also had its issues and was being replaced with a better, more performant, and updated API. How would I ensure all the consumers were aware they had to stop using the old API and, optionally, start using the new one?
My first thought was to block any new consumers from using the old API. By doing that I would limit the usage of the old API to the existing consumers. This sounded like a good first step to take, but how could I implement it? Luckily, the API was using a token-based authentication scheme. I would be able to limit usage to tokens that had been generated before a certain date. Consumers using any other tokens would simply be refused. In fact, the implementation was straightforward, and soon any new consumers weren’t able to use the API. I call this the consumer limitation stage.
But now, how do I know who the existing consumers are so I can tell them I’m about to turn the API off? Well, each authentication token was associated with a consumer. I grabbed the API access logs from the previous three months and extracted the token information. I then used that information to obtain a list of all the consumers that had been using the API recently. This step was crucial because it let me establish a direct communication with all the consumers.
I sent an email to each consumer asking why they were using the API, how crucial was their dependency to the business, and how long it would take them to move to a new API. Having this information was critical because it let me define how long the API should be in a deprecation state and how long the whole sunsetting process would take. I also engaged directly with a few consumers to help them define the implementation plan to move to the new API. I call this the consumer discovery stage.
Having an idea of how long consumers would need to adapt, I defined the deprecation period. In my case, it was three months. The idea was that within three months all the consumers had their solution adapted to using the new API. I sent a communication to all consumers again. This time I explained them that the API was going to be deprecated and they had three months to integrate with the new one. I also shared clear instructions on how to integrate with the new API and offered support from the API producer team in case it was needed.
In addition to offering human-understandable communication, I asked the API producer to add the Deprecation HTTP header field to all responses. Even though this is still an IETF draft, it's now being considered for an RFC. There's an advantage in having a specific HTTP header announcing the API deprecation on every response. By having machine-readable deprecation information API consumers can trigger errors and alarms whenever the API is near its deprecation deadline. I call this the API deprecation stage.
At that point, and when the three-month period has passed, it's time to definitely kill the API. To do that I established a sunset period of one month. Instead of deactivating the API immediately I thought of offering another month just in case someone didn't have enough time to adapt. Again, I communicated the situation to all the existing consumers—fortunately, fewer, at that point—explaining what they would have to do to transition to the replacement API.
During the final one-month period I also set a recurring warning that was sent to consumers every week. This approach was to set a tone of urgency and make consumers fully aware of the situation. Additionally, I asked the producer to add the sunset HTTP header to every response so the consumers would also receive machine-readable information. I call this the API sunset stage.
Finally, when the sunset deadline arrived it was time to deactivate the API. Since deactivating the API might take some time, the first thing to do was to block any further usage from happening. That was done by configuring the API gateway to stop accepting requests to the API endpoints. From that point on no one was able to make requests to that API. In a way, it was as if the API had been deactivated.
However, the API was still deployed and running. To fully deactivate it the API producer had to go through a series of steps. In my case, it required "deprovisioning" the server instances that were running the API, the database holding its data, and removing all the information related to authorization. These were things that required manual action and coordination. And, naturally, it takes some time to get done. Fortunately, we had already blocked the API usage so no consumers were able to make requests. This is what I call the API deactivation stage.
In summary, the steps I took started with limiting the consumption by blocking new consumers, discovering who the existing consumers were and establishing a communication channel, announcing the deprecation of the API and creating a deadline, communicating the sunset date, and finally blocking all consumers and deactivating the API. These are the sequential stages that I took:
Consumer limitation.
Consumer discovery.
API deprecation.
API sunset.
API deactivation.
Did it go well? It depends. From a producer's perspective, it went very well. However, consumers felt they didn't need to migrate to a new API and, at first, didn't understand why the API had to be deactivated. There's a lesson here in improving the communication so everyone is aligned on the reasons behind the actions.
As a final note, during this process, the API producer had to be able to introduce changes. While the API was still being consumed, any critical and security-related bugs had to be fixed and deployed. Any changes that were considered non-breaking were introduced directly into the API we were deprecating. Any other changes went into the new API that would replace the existing one.
Is this a process I would repeat? Probably. The amount of detail needed in the communication with stakeholders is high. The chances of generating problems grow with the number of consumers. I'd repeat this process in an environment I could fully understand. So far, it looks like following these steps is better than simply deactivating the API and hoping everyone will adapt to the change.