Why Your API Sucks

Interfaces above all else - Nov. 5, 2020, 6:46 p.m.

Look, I get it. Making a great API is hard. Nobody claimed it was easy! That being said, there are a phenominally lot of ways to do it wrong. The following is a list of problems that I have personally had in working with various third party APIs. Are these all super serious problems? No. Should I expect every API to not have any of these problems? Of course not; I myself am guilty of a number of these issues! However, the problems remain, and they are indeed problems, so without further ado:

  • Your API doesn't use https. This is pretty basic stuff, c'mon now.
  • Your API has a required nonce. Nonce's do basically nothing at all for security, and are really only good at making it a PITA for clients to consume your API in a distributed manner. At the very least, make it an optional parameter.
  • Your API has rate limits that are ridiculously low, and prevent anyone from feasibly using it. I understand protecting yourself from overloading your systems, but if your systems are so weak I can't feasibly use it, maybe you're fixing the symptom and not the cause.
  • Your API has reasonable rate limits, but doesn't convey back to the user what your remianing quota is, making it impossible to do any sort of intelligent resource management. If you don't let your users make intelligent choices, they never will.
  • Your API rate limiting rules are so complex that they're not feasible to confidently calculate up front. This results in the same outcome as above; if you don't let your users make intelligent choices, they never will.
  • Your API throttles me for a period of time but doesn't offer any indication of when the ban will be over. My only option is to poll your API to check if I'm still banned, which is obviously counter productive for both of us.
  • Your API doesn't return unique identifiers for entities, making it difficult (and sometimes impossible) to de-duplicate entities.
  • Your API returns multiple, different, unique identifiers for the same entity in different endpoints.
  • Your API isn't self consistent, even accounting for eventual consistency.
  • Your API is eventually consistent, but provides no mechanisms to know if the result of one endpoint is "before" or "after" in time from a previous operation.
  • Your API isn't idempotent, or doesn't require an idempotency-like key for idempotency guarantees within a reasonable time window.
  • Your API doesn't offer pagination or any other mechanism to properly traverse a large collection of items. This one is more of an annoyance than critical, but if you have a large collection of data on your API, people will want to iterate over the whole thing.
  • Your API has various query parameters that have to be in a specific order or it won't work. This is entirely too brittle.
  • Your API doesn't use HTTP status codes and instead uses an embeded "error" semantic to convey failure. Now my metrics tracking basic request failure rate have to live at the application layer, and not the http layer.
  • Your API doesn't use error codes to differentiate between failure scenarios, and instead returns a string that is subject to, and does indeed frequently, change. Nothing I love more than discovering that I have a surging amount of "unrecognized" errors because you made a slight formatting tweak in your error messages.
  • Your API returns error in a different place of the returned payload based on what error it was, forcing my error identifying logic to have to look basically everywhere instead of one spot. Actually, this can be generalized to:
  • Your API payload has a different shape / data type based on context outside of what I asked for. I should be able to know the shape of what the result will be, before I actually receive it. Any sort of polymorphic deep nested fields type is confusing and puts application logic into the de-serializing layer. If your API endpoint can return different combinations of results based on context, then make your schema a flat product type over all fields.
  • Your API doesn't have documentation, leaving me to deduce your functionality black-box style.
  • Your API has undocumented behaviour. Inevitably this is only ever found out in production. Your consumers will not be happy.
  • Your API documentation doesn't document all the possible error codes.
  • Your API documentation doesn't properly describe what all the fields in the returned payload are. Am I dumb for not knowing what the (example) st field is supposed to contain? Or you should you just give it a human description in your documentation instead of only telling me that its a float??
  • Your API uses POST for all requests, even read-only endpoints.
  • Your API uses GET for all requests, even state-changing endpoints.
  • Your API doens't provide websockets for updates that consumers would ostensibly want to know about, leaving them no option but to poll. This usually leads to all the rate limiting problems above.
  • Your API isn't versioned, and so I can only assume that it is entirely subject to change with no notice, unless otherwise stated.
  • Your API has different structures & semantics based on which resource I want, probably a result of different internal teams.
  • Your API uses json web token in a way that json web tokens are not supposed to be used, which is too say, basically at all.
  • Your API is only consumable through your custom "SDK" that comes with a bunch of bloat I don't want, and is only available in a language I don't use. If I can't use curl to inspect your API, that's bad.

  • Your API uses numbers for precise decimal numbers. Financial APIs, I'm looking at you.
  • Your API doesn't use ISO 8061 for dates. I'll also accept any form of unix timestamp, but only as a distant second best.
  • Your API doesn't specify what timezone dates are in, and also uses different timezones based on context.
  • Your API internal errors more than 5% of the time 😭
  • Your API just straight up doesn't work properly 👿