Validation and data
Paginate, filter, and sort
Keep collection responses bounded and stable with validated limits, cursors or offsets, filters, and deterministic ordering.
8 minute lesson
An unbounded collection route becomes slower and more expensive as data grows. Pagination is part of the contract from the start.
For the first version, accept a capped limit and non-negative offset, filter by author, and order by creation time plus ID for a deterministic tie-breaker. Return pagination metadata or links so a client knows how to continue.
curl "http://localhost:3000/books?author=Le%20Guin&limit=20&offset=0"
Validate before constructing SQL: reject non-integers and negative offsets, apply a modest default, and cap the maximum limit. Use bound parameters for filter values and an allowlist for sort fields. Add indexes that match real filters and ordering only after inspecting the query and dataset; every index also adds write and storage cost.
Offset pagination is simple but rows inserted or deleted between requests can shift later pages. Deterministic ordering limits ambiguity but does not freeze the dataset. For a busy collection, move to a cursor containing the final sort values, such as created_at and id. Whichever strategy you publish, treat it as contract data: return the next link or cursor, and return an empty successful page when the client reaches the end.
Add validation and parameterized SQL for the collection query, then request two small pages.
Lesson completed