Good design is invisible until it's missing
A well-designed API rarely gets praised directly — developers just use it without much friction and move on. A poorly designed one gets noticed constantly, usually through complaints, workarounds, and defensive code written to guard against its inconsistencies. That asymmetry is a useful signal: if an API keeps coming up in conversation, it's probably not going well.
This isn't only a concern for large public APIs used by outside developers. Internal APIs, used only by a small team, benefit from the same discipline — the cost of an inconsistent internal API just shows up later, as friction inside the team rather than complaints from external users.
The traits that consistently show up in good APIs
- Predictable naming. Once a developer learns the pattern for one endpoint, they should be able to guess the pattern for a related one without checking the docs.
- Consistent error handling. Errors should return the same shape and use meaningful status codes, so client code can handle failure in one place instead of many.
- Sensible defaults. Optional parameters should have defaults that cover the common case, so a basic request doesn't require reading the entire reference first.
- Versioning that doesn't break existing clients. Changes should be additive where possible, with breaking changes clearly versioned rather than silently shipped.
- Documentation with real examples. A working example for the common case is worth more than an exhaustive but abstract parameter list.
Naming deserves special attention here, since it's the part developers interact with constantly. A resource called users in one endpoint and members in another, referring to the same underlying concept, forces every consumer of the API to memorize an exception instead of relying on a pattern.
A small example of the difference
Consider two APIs for fetching a list of items. One returns a bare array, with no way to know if more results exist. The other returns an object with the items, a total count, and a cursor for the next page. The second design costs slightly more to implement upfront, but it avoids a painful breaking change later when pagination inevitably becomes necessary.
Designing for the client, not the database
A common mistake is shaping an API around the internal database schema instead of around what a client actually needs. The two often diverge, and an API that just mirrors internal tables tends to leak implementation details that make future changes harder.
Reviewing an API before it ships
A short review pass before an API goes live catches most of the problems that are expensive to fix later. Walking through the common use cases as if you were an unfamiliar developer — not the person who built it — tends to expose awkward naming and missing defaults quickly. Checking that every error path returns a consistent, useful shape, not just the success path, is worth doing deliberately, since error handling is usually an afterthought during initial development.
It's also worth writing the example request and response in the documentation before writing the implementation, not after. Doing it first tends to reveal design problems while they're still cheap to change, rather than after client code already depends on the shape you originally chose.
Summary
- Good design is invisible until it's missing
- The traits that consistently show up in good APIs
- A small example of the difference
- Reviewing an API before it ships
Frequently asked questions
Should every API be RESTful?
Not necessarily. REST is a solid default for many use cases, but GraphQL or RPC-style APIs can be a better fit depending on how clients need to query the data.
How important is versioning for a small internal API?
Still important, though less strict than a public API. Even internal consumers can break unexpectedly when a response shape changes without warning.
What's the biggest mistake teams make with API design?
Designing the API around the database schema rather than around what clients actually need, which tends to create awkward, leaky endpoints.