Matt White

Matt White

developer

Matt White

developer

7 Deadly API Sins

Maximum suffering - minimal effort

This guide and the descriptions below are fictitious. No identification with actual APIs (living or dead) is intended or should be inferred - especially not seller, vendor, marketplace, or advertising APIs from companies named after notable rivers.

1. Keep your documentation accuracy as close to 66.6% as possible

Obviously 66.6% looks rather insidious, but that’s purely coincidental.

Found through extensive trial and error, 66.6% is the “golden ratio” for API documentation. Your docs have to be accurate enough to keep API users referencing them, but inaccurate enough to cause untold suffering.

The most fun part of this is redirecting users to the docs when they inevitably open support tickets about everything else in this guide.

2. Use completely different ID’s for your UI and your API

Using different ID’s is only half the battle; you need to make sure there’s literally no way for API users to map between the IDs in the UI and the IDs in the API.

Make integrators try to guess which resource is which based on fields that aren’t unique in any way. That’s half the fun.

Bonus points if you have a third layer of completely separate object IDs for internal use.

3. Rotate HTTP codes and messages for the exact same errors

API integrators get complacent if you leave their error handling intact for too long.

As a rule, make your errors as vague as possible, but when you can’t avoid specificity, make it a point to reword and reclassify errors at regular (but not too regular) intervals.

You can rephrase “this region is not supported” in many ways - “support is not available in this region”, “support for this region is not yet implemented”, “this operation is not available in this marketplace”, etc.

And don’t forget to change your response codes. Change some 429 Too Many Requests to 401 Unauthorized’s. Change some 401 Unauthorized’s to 403 Forbidden’s. Hell, change some 400 Bad Request’s to 200 OK’s - you get the idea.

The important thing is to make sure your errors change all the time. Let loose and don’t be afraid to experiment!

4. Use PATCH and PUT interchangeably

HTTP verbs are more what we’d call “guidelines”, after all. Use PUT to mean PATCH on 70-90% of endpoints. While tempting, don’t make the mistake of doing it too consistently - your users will figure it out.

For the 30-10% of the time when you really mean PUT, it’s quite fun to require fields that the user has no way of retrieving - never return all the required data in your GET endpoints.

If API users ask about these mystery fields, pretend to miss the point and lecture them about how PUT requests work. Direct them to the documentation.

5. Reuse old ID’s for new objects - uniqueness can’t compete with frugality

When API objects can finally be retired, it would be wasteful to retire the unique identifier with them. With rising support for renewables across virtually all demographics, the only thing better than a unique ID is a recycled ID.

Sustainable practices and invalidating countless amounts of user data at the same time? What’s not to love?

Like with #2, it’s critical to ensure that API users have no mechanism to determine which ID maps to which object. It’s pointless to invalidate swaths of data when your users can simply “undo it” by remapping millions and millions of foreign keys.

6. Consistency is the enemy of curiosity

In a vacuum, different teams will naturally produce very different APIs. Inertia is on your side - the hard part is maintaining that vacuum.

The sad truth is - many engineers will naturally want to provide a consistent experience for users. The best defence is to ensure that your devs have no concept of what ‘consistent’ would even look like.

Block teams off from existing work and documention. Cross-team coordination is completely out. If you find your team building consistent APIs - even accidentally, fabricate “user feedback” to guide them in a different direction.

7. Throttling and rate limits are best communicated by choosing error responses at random

More and more, API statistics are showing a sharp drop in API usage immediately following HTTP 429 Too Many Requests responses. This kind of user disloyalty will not reflect well on the team when placed in the quarterly powerpoint presentation.

How do you keep your users sending requests when you’re throttling them? Simple - you make sure they have no idea they’re being throttled.

Send 429 Too Many Requests responses just often enough to make API users think they can rely on it. Now rotate in 400 Bad Request, 401 Unauthorized, 403 Forbidden, 500 Internal Service Error, 502 Bad Gateway, 504 Gateway Timeout - all seemingly at random.

As a bonus, you can place the user authentication tokens in the error response body. This way, API consumers who save unexpected errors might accidentally log the auth tokens in plaintext.

Ignore any support tickets that suggest exposing credentials in response bodies may be inadvisable. Direct them to the documentation.

Honorable Mention: No incremental data ingestion - no pagination without missing rows

This one is easy:

  • don’t sort by creation time
  • don’t allow users to specify sort order

This works best for data that’s constantly having rows inserted. API users grab page 1 - and before they’ve grabbed page 2, you insert random rows that land in page 1. Now the hapless integrator will have to deduplicate the page 1 rows that come in again on page 2.

And the best part - if they ever want the new rows they missed - they have to walk through every page yet again.

A little less terrible every day.