API Shapes for UI
Designing APIs for what screens actually need — reducing round trips without coupling the backend to the interface.
Definition
The shape of an API determines how many requests a screen makes and how much unused data crosses the network. Both matter disproportionately on mobile networks.
The problem with a general-purpose resource API
A strictly resource-oriented API requires the client to assemble a screen from several calls:
/orders/123, then /customers/456, then /products/789 for each line. On a high-latency connection
that is seconds of sequential round trips, and it is the dominant cost.
It also over-fetches: each resource returns everything, and the client uses a fraction.
The options
Backend for frontend. A thin backend per client class, aggregating and shaping exactly what its screens need. Owned by the client team, which is the property that makes it work — a BFF owned by a central team is the same bottleneck with an extra hop.
A query language. Clients request precisely the fields they need in one round trip. Solves over-fetching and round trips well; introduces query complexity, caching difficulty and a genuine denial-of-service surface if query depth and cost are not bounded.
Compound or expandable resources. Conventional REST with an include parameter. Simple, cacheable,
and less flexible — frequently sufficient and under-used because the alternatives are more fashionable.
The rule that keeps it healthy
Aggregation belongs close to the services, not in the client. Whichever mechanism is chosen, the fan-out should happen inside the data centre where round trips cost a millisecond, not across the user's mobile network where they cost hundreds.
And the aggregating layer must have per-call timeouts within an overall screen budget, and must degrade partially — rendering the screen without the failing section rather than failing the response. Otherwise it aggregates the latency tails of every service it calls.
What to avoid
Coupling the backend's domain model to a screen's layout. An endpoint named after a screen becomes obsolete when the screen changes, and it multiplies as screens do. Shape by what the client needs, not by where it is displayed.
Failure scenarios
- Six sequential requests to render one screen.
- Over-fetching large payloads on mobile connections.
- Aggregation in the client, so round trips cross the slow network.
- Unbounded query cost, allowing an expensive query to be constructed.
- Endpoints named after screens, coupling the API to the interface.
Interview question
"A mobile screen makes six sequential API calls and takes two seconds on a good connection. What are your options?"