Web Development

Designing an API your own front end will not fight

Most internal API pain comes from a handful of decisions: resource shape, error handling, pagination and versioning. Getting them right early is cheap.

Key takeaways

  • Design endpoints against the screens they serve, not against pure entity purity.
  • Consistent, actionable error bodies save enormous client-side effort.
  • Cursor pagination beats offset for large, changing collections.
  • Publish a compatibility policy before the first consumer exists.

Shape resources around the client's needs

A purist resource model that forces the front end to make six requests to render one screen is not a good API, however clean the entity boundaries look. Design endpoints against the screens they serve.

That does not mean one bespoke endpoint per screen, which becomes unmaintainable. It means allowing sensible embedding of related data, so a page can be assembled without a waterfall of dependent requests.

Errors that a client can act on

Return the correct status code and a consistent body containing a machine-readable code, a human-readable message and, for validation failures, the field-level detail.

  • 400 for malformed requests, 422 for semantically invalid ones.
  • 401 for unauthenticated, 403 for authenticated but not permitted — these are routinely confused.
  • 404 when the resource genuinely does not exist for that user.
  • 409 for conflicts, with enough detail for the client to resolve.

Pagination, filtering and sorting

Decide once, apply everywhere. Cursor pagination is more reliable than offset for large, changing collections, because offsets shift as records are inserted.

Return the page metadata the client needs to build its interface — whether more pages exist, and how to request them — rather than requiring the client to guess.

Versioning and change

Additive changes rarely need a new version. Removing a field, changing a type or altering the meaning of a value does. Decide your compatibility policy before the first consumer exists, and publish it.

In practice a version in the URL path is the least surprising approach for internal APIs. Whatever you choose, the important part is having a deprecation process with a timetable rather than breaking clients without notice.

Documenting and evolving the contract

Generate documentation from a machine-readable specification so it cannot drift from the implementation. Hand-written API documentation is inaccurate within weeks, and inaccurate documentation is worse than none because it is trusted.

Publish example requests and responses for every endpoint, including error cases. Consumers spend most of their integration time on error handling, and undocumented error shapes are where integrations break.

Where the API is public or has many consumers, provide a changelog and a way to be notified. Silent changes to a contract are the fastest way to lose the trust of the teams building on it.


Frequently asked questions

REST is simpler to build, cache and debug, and suits most internal APIs. GraphQL earns its complexity when many different clients need to request different shapes of the same data and a front-end team will exploit that flexibility.

JSON for application clients. Returning server-rendered fragments is a legitimate pattern for progressively enhanced sites and is a different architecture, not a worse one.

Generate documentation from a machine-readable specification such as OpenAPI so it cannot drift from the implementation. Handwritten documentation is out of date within weeks.

Working on this?

A conversation with our team, no charge and no obligation.

Book a conversation