Back to blog

APIs Nobody Hates

Design principles for building APIs that developers actually enjoy using.

A bad API is one of the most expensive mistakes you can make. Every consumer has to work around your design decisions forever. Here's how I design APIs that don't make people miserable.

Be predictable

If GET /users returns a list of users, then GET /products should return a list of products in the same format. Same pagination. Same filtering syntax. Same error structure. Consistency is the single most important quality of an API.

A developer who learns one endpoint should be able to guess how every other endpoint works. If they can't, your API has a design problem.

Use the right status codes

200 means success. 201 means created. 400 means the client messed up. 401 means not authenticated. 403 means not authorized. 404 means not found. 500 means the server messed up.

That's the whole list for 90% of APIs. Don't return 200 with an error body. Don't return 500 for validation errors. Use the codes the way they were designed to be used.

Error messages are UI

When something goes wrong, the developer consuming your API needs to know: what failed, why it failed, and what they can do about it. A good error response looks like this:

  • A machine-readable codeVALIDATION_ERROR, not ERR_001. Something a developer can switch on.
  • A human-readable message — "The email field must be a valid email address." Not "Invalid input."
  • The field that failed — Point to exactly where the problem is. Don't make them guess.

Paginate everything

Every list endpoint should be paginated from day one. Not "when you have enough data." From day one. It's a trivial amount of work upfront and prevents cascading failures when your database grows.

Use cursor-based pagination, not offset-based. Offsets break when data changes between requests. Cursors don't.

Version your API

Put the version in the URL: /api/v1/users. Not in headers. Not in query params. In the URL, where it's visible and obvious. When you need to make a breaking change, create v2. Keep v1 running until everyone has migrated.

Document by example

Developers don't read API documentation top to bottom. They scan for an example that looks like what they're trying to do, copy it, and modify it. Make sure every endpoint has a complete request/response example with realistic data. Not string and number — actual values.

Swagger/OpenAPI is the bare minimum. A good API has a getting-started guide with copy-paste examples that work on the first try.

The golden rule

Before shipping an endpoint, use it yourself. Build a small client. Try to do real things with it. If it feels awkward to use, it is awkward. Fix it before anyone else has to deal with it.

The best APIs feel invisible. You don't notice them because they just work the way you expect. That's the goal.