A developer platform's REST API returns collections that can contain millions of items. Which design decisions separate an API that scales from one that does not?
Show the full answer Hide the answer
The decisions that matter
1. Cursor pagination, not offset pagination. Offset pagination (?page=500) requires the database to
scan and discard everything before the offset, so page 5,000 is dramatically slower than page 1 — and the
cost grows with depth precisely for the clients doing full traversals. Worse, it is incorrect under
concurrent modification: an item inserted while a client paginates causes items to shift, so the client
silently sees duplicates or misses entries.
Cursor pagination encodes a position in a stable sort order. Cost is constant per page and results are consistent under insertion.
2. A maximum page size, enforced. Without one, a client requests everything and either times out or takes the service down. The limit is not an inconvenience; it is a capacity control.
3. Sparse fieldsets or explicit expansion. Returning every field of every related object by default means the expensive case is the default case. Let the client ask for what it needs — and default to the cheap response.
4. Rate limits that are visible in every response. Remaining quota, limit and reset time as headers, so a well-behaved client can pace itself rather than discovering the limit by being rejected. This is the difference between an API that clients can integrate reliably and one they must guess about.
5. Conditional requests. ETags and If-None-Match so a client polling for changes gets a cheap
not-modified response. For a platform with many polling integrations, this is a substantial fraction of
total load, and it is free to provide.
6. A separate mechanism for bulk and historical access. Pagination is for browsing, not for exfiltrating the whole dataset. Clients who need everything should get an export or an event stream — otherwise they will use pagination for it, and your API's load will be dominated by full traversals.
The decision that shapes everything else
Whether clients poll or subscribe. An API that only offers polling will be polled — by thousands of integrations, most of which find nothing changed. That load is pure waste and it grows with your ecosystem's success.
Offering webhooks or an event stream converts that from "every client polls every minute" to "we notify when something happens", which is a fundamentally better scaling relationship. Platforms that add this late discover that polling load already dominates their infrastructure, and that migrating an ecosystem off polling takes years.
The lesson
REST API design at scale is mostly about making the cheap path the default and the expensive path explicit — bounded pages, requested fields, conditional requests, and a purpose-built route for bulk access. An API whose default response is expensive will be used expensively.