A fixed response shape forces every API into a choice nobody actually wants to make: always return everything a resource could possibly include, so a mobile client rendering a simple list row downloads and parses a customer's full address, order history, and internal metadata it will never touch; or return a deliberately minimal representation, so a dashboard that genuinely needs the related customer, the line items, and each item's product has to issue three or four additional round trips just to assemble one screen. The first choice is over-fetching. The second is under-fetching. A single fixed shape can be tuned to minimize one, but never both, because different consumers of the identical resource want genuinely different amounts of it.
Under-fetching has a specific, well-known failure pattern: a client fetches a list of orders, then loops over that list issuing one additional request per order to fetch its customer, turning what should be one request into N+1 requests whose total latency is dominated by network round trips rather than actual work. Over-fetching has a quieter cost that shows up as aggregate bandwidth and parse time rather than a dramatic failure — cheap to ignore on a fast connection, expensive on a slow mobile network multiplied across millions of requests.
The fix isn't picking a better fixed shape — it's giving the client a documented, bounded way to say what it actually needs: sparse fieldsets to trim a response down, and explicit, allowlisted expansion to inline exactly the related data a specific consumer needs without forcing a follow-up round trip for it.
Analogy🏏Cricket
🏏 Think of it like cricket: A broadcaster's graphics package for a single delivery isn't one fixed overlay reused identically for every viewer and every moment — a producer chooses, ball by ball, exactly what the audience needs right now: a full player-profile card with career stats when a batter walks out for the first time, a minimal score-and-required-rate strip during a tense final over when nobody wants their view of the actual cricket blocked by extra graphics, a detailed pitch map only when a commentator specifically calls for one. Showing the full profile card on every single ball would clutter the broadcast with information nobody's asking for in that moment; showing only the bare score during a batter's dramatic milestone would leave out context the moment genuinely calls for. Neither one fixed overlay serves both moments well, which is exactly why the graphics package is built to be selected per moment rather than locked to one configuration. Just as a producer selects exactly which graphics a given moment calls for rather than reusing one fixed overlay for every situation, an API should let a client select exactly which fields and related data a given request calls for rather than reusing one fixed response shape for every consumer. Just as the underlying data — the player's full stats, the ball-by-ball feed — exists once regardless of which graphic is currently selected, a resource's full representation exists once on the server regardless of which fields or expansions a particular client happens to request. The insight is that one dataset serving many genuinely different consumers needs a way to be shown differently to each of them, not a single compromise shape trying, and failing, to serve everyone equally badly.
🏏 Showing the Cricket analogy — a Cricket version isn’t available for this concept yet.