Top 10 API Worst Practices

We try to stay positive at ProgrammableWeb. We've talked a lot about the keys to a great API, but not so much about what some of the lesser APIs do. And, with a directory of over 6,000 APIs, you'd better believe we've seen some worst practices.

  • Poor error handling
  • REST APIs that ignore HTTP rules
  • Exposing your raw underlying data model
  • Security complexity
  • Unexpected and undocumented releases
  • Poor developer experience
  • Expect an MVC framework "gives" you a great API
  • Assume if you build it they will come
  • Inadequate support
  • Poor documentation

Many of these issues came up in the developer survey that said Facebook causes the most developer pain.

For other tips on the positive side, see what makes a great API.

Photo by Richard Riley

 

Comments (5)

[...] An ever-evolving list of worldwide stores of Linked Open Data, primarily from governments… Top 10 API Worst Practices (Programmable Web) – How to ensure that a newly-published API is not used… Five Keys [...]

[...] API Worst Practices: You probably know about the best practices for an API but what about the worst ones? This article gives you the list. [...]

First-Last

As with the MVC point, the same actually applies to REST. Not all APIs need to be REST and most that claim to be actually do not meet all REST requirements. REST is intended to either solve a number of problems or enable a number of features. These come at a cost. You're not guaranteed to gain a benefit from implementing every single REST feature, some of which require that you work within a number of restrictions. There are some things that if you don't use REST you can't do or you can't do in certain scenarios. However it works the other way as well. If you use REST there will be some things you can't do.

In nearly every case I've seen not only does an API not need to be REST but there's no benefit to overrusing HTTP transport specifics. If you're not using HTTP methods and codes to gain something, you're probably better off not doing it. Otherwise you're doing it simply because someone in the middle of the jungle said loudly to do so then parrots spread it across the jungle like wild fire. If you don't understand why you're doing something, don't do it. If in programming you don't know why you're using all of the practices you're using, you're doing it wrong. It's not scouts where you have to collect badges. I believe unfortunately this is based on how job descriptions are written with most people doing it because they feel they have to as part of the social contract like wearing overly expensive brand names to fit into a crowd that does the same.

A major anti-pattern for this is people trying to squash all kinds of application messages into HTTP codes. Some of the worse cases involves exceptions from deep in the interior of an application that shouldn't be concerned with transport or the application boundary throwing Error404 exceptions (such as somewhere in the database driver). In other cases having API calls that don't quite match HTTP methods and get broken up in horrible ways to fit or simple go on mismatched.

In general, your API should start off transport agnostic (to be fair I lie a little as a lot of APIs are only ever going to be HTTP) and error codes or methods should not be used for application to application communication. They should be exported and mapped from internal errors or methods and defined on the boundary. Separating application from transport is usually beneficial. REST is heavily tied into transport, specifically HTTP which is something that you might not actually need. Unfortunately what most people do in this case is heavily tie their applicacationing into HTTP. There are always exceptions but generally speaking this is being done just because and it can make things worse.

Apart from success/fail (often 200 and !200) there really aren't any HTTP codes that are universally useful. Even with custom codes you're quite limited in what you can express (consider 404, what wasn't found when you tried to hit a/b/c, transport considers the whole thing but your application can be cleverer than that and know that a was not found using feedback in the payload). Some are more useful to common situations than others. Unfortunately these often aren't used properly either. An error message like bad request might be useful as you can cache that (all the way up to client even) if you version your API properly. However what you see is people sending that even for non-deterministic transient errors (such as trying to get at something in the database that's not there now but could be in future). I don't use these codes and wouldn't without checking the RFC. I would imagine that bad request has to refer to the entire request and bad input only the input which must be invalid for all requests to be useful. I can't really know though without verifying and unfortunately most people wont go beyond the blog or even the article to the comments section.

The situation is deceptive. HTTP methods and codes look simple. It also seems useful to export information as far up the chain as possible. There's a conflict here between being transport agnostic and payload agnostic (for example, authentication failed but the payloads can come in many forms so by setting it transport doesn't have to care about payload specifics which usually falls on to the application). There's no rule that says it's always possible to map one exception to a single action beyond as a generic failure. I've had people screaming down my ear when in one case a failure in a foreign service I have no control over would have been resolved best with a service temporarily unavilable for exactly an hour error automatically rather than simply computer says no using HTTP codes to express that. However in another situation with exactly the same failure pattern that action would have been catastrophic to the business. In reality, not all complex things can be reliably mapped to simple things. Some things will be ambiguous. People get caught up making best guesses or going for the average case (usually the first they saw) and on just making error messages meet the description of the error. When it comes to questions like what is the purpose of setting these codes, who is the audience, what's the purpose? When it comes to REST and utilising these you'll find that sadly the answer to all of those kinds of questions consists of all the possible answers and more.