Technology

The API Design Decisions That Decide How Fast a Web App Can Grow

4

Good API design for a web app means modelling endpoints around resources rather than screens, planning for versioning before the first breaking change, keeping error responses consistent, building in pagination and rate limiting from day one, and generating documentation from the API’s own schema rather than writing it by hand. Most web app teams treat the API as plumbing: something that moves data between the frontend and the database, built quickly so the interesting work of screens and features can start. Then a mobile app needs the same data. Then a partner wants a feed. Then someone adds a second frontend framework because the first one aged badly. Every one of those moments exposes decisions that were made in a hurry months earlier, and by then they are expensive to unwind.

Key Takeaways

  • An API contract should be designed around the resources it represents, not the screens that happen to consume it first, because screens change far more often than the underlying data model.
  • Versioning needs a plan before the first breaking change is needed, not after, since retrofitting version negotiation onto a live API disrupts every existing client.
  • Consistent error responses across every endpoint save far more developer time than any single clever feature, because inconsistent errors force every client team to write defensive code around the exceptions.
  • Pagination, filtering and rate limiting should be built in from the first release, since adding them later means changing a contract that other systems already depend on.
  • Documentation that is generated from the API’s own schema stays accurate for longer than documentation written and maintained by hand.

A well-designed API tends to be invisible in exactly the way good infrastructure should be: nobody notices it until it is missing. The practices below are less about elegant code and more about reducing the number of times a team has to say sorry to a client that depended on something the API used to do.

Model resources, not screens

The single most common source of API sprawl is building endpoints that mirror a specific page rather than the resource that page displays. A dashboard needs a user’s name, their recent orders and their account balance, so it is tempting to build one endpoint that returns exactly that shape. It works well until a second screen needs the user’s name and their support tickets instead, and now there are two endpoints returning overlapping but slightly different views of the same underlying entity.

Designing around resources instead means an API exposes `/users/{id}`, `/users/{id}/orders` and `/users/{id}/tickets` as separate, composable endpoints, and lets the client assemble the view it needs. This costs a little more up front, usually an extra network request or two, but it means the API’s shape reflects the data model rather than a screen that will be redesigned within a year. Microsoft’s own architecture guidance on RESTful API design makes this point directly: model the API around the business entities and their relationships, not around a particular consumer’s convenience. More detail on how this plays out in practice for client web apps is available at https://wearearch.com/uk/web-app-development-uk.

Developer checking a phone next to a laptop showing code on screen

Decide how the API will change before it has to

Every API will eventually need a breaking change, whether that is renaming a field, changing a data type or removing a deprecated endpoint. The question is not whether this happens but whether the team has a mechanism ready for it. Version negotiation, whether through a URL segment, a header or a media type parameter, needs to exist from the first public release, even if only one version is ever shipped for the first year.

Retrofitting versioning onto a live API is one of the most disruptive changes a web app team can make, because every existing client has to be touched at once.

The alternative, and it is common, is an API that simply changes shape underneath its consumers and expects every client to update in lockstep. That works while there is one client controlled by one team. It stops working the moment a second team, a partner or a mobile app depends on the same contract, because their release cycle is no longer the same as the API’s.

Make failure predictable

Nothing burns more developer hours across a web app’s lifetime than inconsistent error handling. An endpoint that returns a 200 status with an error message buried in the response body, sitting next to another endpoint that correctly returns a 404, forces every client to write bespoke handling for each one. RFC 9110, published in June 2022 as the current specification for HTTP semantics, defines a full and precise set of status codes for exactly this reason, and using them consistently means a client can write one error-handling path instead of dozens.

The same logic applies to the shape of error payloads. A consistent structure, such as a machine-readable error code alongside a human-readable message, lets client applications build generic handling that works across the whole API rather than endpoint by endpoint. The OWASP API Security Top 10, updated in 2023, goes further and treats inconsistent or overly verbose error messages as a genuine security risk, not just an inconvenience, since a stack trace leaked in a 500 response can hand an attacker information they should never have had.

Close-up of a hand holding a sticker with the word JSON in braces

Build for scale before scale is the problem

Pagination, filtering and rate limiting are the three features most often left out of a first release because nobody is asking for them yet. They are also the three features that are hardest to add later without a breaking change, because adding a `page` parameter to an endpoint that previously returned every record changes what existing clients receive by default. The safer order is to build these in from the start, even generously, so that when the data set grows the contract does not have to.

Rate limiting deserves the same early treatment. An API without limits works fine with one internal client and starts failing in unpredictable ways the moment a second client, or a misbehaving script, sends more traffic than the backend can absorb. A clear limit, communicated through standard headers, lets client developers build around it deliberately instead of discovering it through an outage.

Two colleagues looking together at a desktop monitor in an office

Let documentation follow the contract, not the other way round

Documentation written by hand drifts from the API almost immediately, because updating the docs is rarely anyone’s first priority after shipping a change. Generating documentation directly from the API’s schema, whether that is an OpenAPI definition or a similar format, keeps the two in sync by construction rather than by discipline. It also gives new developers, whether inside the team or at a partner organisation, a single source of truth they can query interactively rather than a document that might be a version behind.

Stack Overflow’s engineering blog made a related point in 2020 about API design generally: the goal of a good API is that a developer who has never seen it can guess correctly how it behaves, and clear, generated documentation is one of the fastest ways to get there. A humble but relevant example of this discipline in practice is Arch’s web app development service, which treats the API contract as a first-class deliverable rather than an afterthought bolted on once the frontend is finished.

Frequently Asked Questions

How early should API versioning be planned in a new web app?

Versioning should be planned before the first breaking change is needed, ideally at the project’s outset. Adding version negotiation to a live API disrupts every client already depending on it, whereas building it in from the start costs very little extra effort.

What is the most common mistake in web app API design?

The most common mistake is designing endpoints around specific screens rather than the underlying resources. This produces overlapping endpoints that duplicate data in slightly different shapes and become harder to maintain as new screens are added.

Does pagination need to be added from the first release?

Yes, in most cases. Adding pagination later changes what a client receives by default from an endpoint that previously returned everything, which counts as a breaking change even though it looks like a minor improvement.

Why do inconsistent API error responses matter so much?

Inconsistent error responses force every client application to write custom handling for each endpoint instead of one shared error-handling path. This slows down every team that consumes the API and can also leak information that should stay private.

Should API documentation be written by hand or generated automatically?

Generated documentation, built directly from the API’s schema, stays accurate far longer than hand-written docs because it updates automatically whenever the schema changes rather than depending on someone remembering to update a separate file.

Sources

Zayd Dana
the authorZayd Dana

Leave a Reply