When, a couple of weeks ago, developers kicked up a fury over Yahoo!’s surprise deactivation of a stock quote “API," I looked into the matter and discovered that it really wasn’t an API that they were using, nor was the service (a CSV download feature of Yahoo! Finance) intended for automated programmatic consumption by developers.
An untold number (potentially thousands) of developers apparently discovered the service's feature approximately 15 years ago and have been relying on it ever since. When Yahoo! discontinued the feature, a lot of applications that relied on it also broke, unleashing a wave of disappointment.
Developers were miffed about not getting a warning. But since the feature wasn’t officially an API — and certainly not the sort that developers normally sign-up for -- it’s impossible to blame Yahoo! Normally, when developers sign up to use an API, they must supply an email address. In exchange for this sort of registration, the API provider issues a set of credentials for the developer to use when accessing the API. But, without the email addresses for all the developers that were leveraging the CSV download capability, Yahoo! had no sure-fire way of getting in touch with all the developers that were relying on it.
This episode is a reminder of two important lessons. First, any developers that programmatically and anonymously rely on unofficial “APIs” in this fashion are taking a huge risk of a surprise shutdown. Second, running open APIs that are anonymously available without any form of registration (which many API providers still do) is a really bad idea (but one that Yahoo! is not guilty of since it never intended to offer the service for developer consumption anyway).
It wasn’t until after I published my findings that I began to think more holistically about the challenges that service operators have when it comes to warning developers of important upcoming changes to an HTTP (Web-based) service that may affect them or the applications that rely on their service. Whereas a service operator like Yahoo! can throw a pop-up window in front of end users that only works for humans and says something like “Warning: This service will be down for maintenance over the weekend,” there’s no standard for how to issue a message like that to a machine in a way that the machine would know what to do about it.
As a result, all of today's best practices for keeping developers in the loop involve some sort of out-of-band notification. I started to wonder if that’s something that we in the API industry could fix. Before leaning into a fix, let’s review some of the best practices for keeping developers in the loop.
Require Developers to Register
First, think twice before leaving an API wide open without requiring any form of registration or authentication. If you don’t know who’s using the API, you have no way of contacting them about anything and you could ultimately end up with egg in your face for having to kill a service.
Once you have email addresses for all the developers who consume your API, you have an easy way to get in touch with them to keep them apprised of anything they need to know about; upcoming system maintenance, new resource availability on an existing API, new versions about to launch, old versions about to retire, etc.
Offer a ChangeLog via RSS
Second, pretty much any service you launch should be accompanied by an RSS-enabled ChangeLog page. At bare minimum, it gives developers something to check periodically (or to subscribe to via an RSS reader) to keep abreast of any upcoming issues that might interfere with the functionality of their apps.
Clear Notifications on Your Website
Not that it would have helped the developers in the case of the shutdown of the Yahoo! Finance service (because it wasn’t officially an API), but more online API developer portals and documentation should prominently display a notification of upcoming changes that will impact developers and their applications. A good example of this is how the API provider Discord (a Skype-like service that’s very popular with gamers) does it:
Although it's less of a notification, we like how Sygic Travel clearly articulates what the current version of its travel API is. Without this, developers might not know which version is the current version because different versions are typically documented using separate pages that often lack any linkage to one another (although, as can be seen in Sygic’s case, there’s a version navigator).
There are of course other on-site opportunities. For example, many API providers run a blog that’s authored by members of their developer relations teams and blogs are perfect for putting the word out about upcoming changes that will impact developers and existing applications.
But what if it’s a situation like the case with Yahoo! where the service provider really has no idea who or what is consuming the API? Or, what if the likelihood that developers are using one of the aforementioned out-of-band methods to stay informed is low?
As it turns out, there are actually a few different non-standard in-band approaches. In other words, ways to package an important notification into normal API responses so that developers get notified programmatically.
For example, as noted in this blog post, Clearbit includes an X-API-Warn header. Your code (if you’re a developer), can keep watch for such a header. Additionally, as indicated in the post, all of Clearbit’s SDKs have been developed to watch for this error and react by posting a warning to STDERR. Writing a bit of code to monitor STDERR and kick-off some sort of notification workflow to get word of upcoming changes into the hands of developers (via email, SMS, etc.) is a trivial task for developers.
Another approach, discussed on StackOverflow, involves the usage of the generic HTTP warning status code 299.
This raises an important point about HTTP status codes. On first blush, one might think they could just use one of the many non-2xx status codes (200, etc.). For example, one of the 5xx (500, etc) error codes which implies a server error. The problem with this is that well-developed code will often branch into an error-handing routine if it sees anything but a 2xx error code. In order to involve HTTP status codes in the solution, a successul response must still be perceived and processed as though there were no errors while also bearing a warning message about an upcoming issue with the service.
Enter the 299 HTTP status code. Technically speaking, 299 is not an error. It can indicate success while also serving as warning. In other words, since it’s still a 200-series code, it implies that the API call was successful, but that there’s additional information to consider.
The StackOverflow post provides examples of how API providers might extend the code with details that developers can programmatically digest. Provided the API documentation of such a feature is really well done and thought-out, an API provider could theoretically extend 299 with meaningful sub-codes. For example a subcode (ie: “V25” where the “V” indicates its a versioning issue) for pending deactivation and another for a scheduled downtime-for-maintenance warning (ie: “M14” where the “M” indicates it’s a maintenance issue).
The idea is by no means perfect. For example, there’s plenty of code out there that looks for an exact match to the HTTP 200 status code before branching-off to a “success” routine. Anything that's not an exact match to a 200 status, like a 299, might get ignored. So, for some developers, issuing a 299 status vs. a 200 status could be the equivalent of a breaking change to the API contract.
Additionally, going back to what Clearbit had to do to its SDKs (to properly account for the presence of some sort of warning in an otherwise successful API call), SDKs would have to be updated and any developer relying on an existing or third party SDK for a given API might run into trouble depending on how the older SDK was coded (is it generically looking for 2xx success or only 200?).
Like third party SDKs, the downside of offering such extensions is that some of the client side frameworks for consuming APIs will very likely ignore such extensions by default. For example, one such popular client framework is SuperAgent. As can be seen from Super Agent’s error handling documentation, the error information will be null if the API call is successful (which presents a bit of conundrum when it comes to returning a successful API call at the same time a warning (but not a full-blown error) is being issued. SuperAgent is open source which means that developers can fork it to address these ideas. But forking a codebase to deal with something non-standard can turn into an overburdensome long term commitment.
For an idea like HTTP 299 to work across the API economy, there would need to be universal adoption of it based on some widely accepted best practices and defacto standards. For example, maybe a standard vocabulary for the extensions with different classes of codes mapping to different types of warnings. This would be much better than proprietary extensions that might be different from one API provider to the next. Even Web browsers could support such extensions. If such standards existed, frameworks like SuperAgent would very likely incorporate that standard into some future version thus relieving developers of having to maintain their own forks.
The idea of extending HTTP status codes will be viewed by some as problematic for the REST architectural style. But those concerns might be assuaged if there was a standard vocabulary that all API providers complied with. After all, from one API provider to the next, today’s HTTP status codes already mean different things which in turn amounts to the sort of tight coupling between consumers and providers that REST purists hate.
One other in-band idea would be to add a notification every time a JSON payload was returned. For example, an additional key:value pair that, if present, always meant there was some in-band message for the developer to act on. This could easily be added without breaking the existing API contract. But it also increases the payload size. Like with the 299 idea, it might suffer from the non-standard vocabulary problem while being problematic for existing SDKs and frameworks. But the biggest problem I see with it is that with the Web, not every API response involves a data payload that can be appended in this way. But every response does involve a header and so, to me, a solution that involves the header is probably better (hey, that’s catchy — “the header is better”).
Finally, there’s one last approach I know of that merits mention. In a presentation about API microversioning given by NetApp software engineer Clinton Knight and HP Enterprise software engineer Scott D'Angelo at last year's OpenStack conference in Barcelona, the pair discussed a secondary "versions API”; one that runs sidecar to a primary API in such a way that it can be interrogated by the developer in order to figure out things like the API's current version, the range of supported versions, and the other primary versions (ie: 1.0) that are still supported.
However, since a sidecar "versions API" involves a separate endpoint, API providers should only consider this approach if they’re willing to essentially double the resources associated with running their APIs. Also, this approach would not have worked for Yahoo!. Had the 299 approach been in place as an industry standard or best practice, Yahoo! could have started sending 299 warnings before going cold turkey. Developers might have detected it and a win-win situation where Yahoo! continued the service at a cost to developers (who might have been happy to pay just so their apps didn't break) might have emerged.
I'm interested in any an all feedback to this idea. So, leave your thoughts in the comments section below or reach out to me directly at firstname.lastname@example.org.