Lists Required
Page lists with cursors
Return every list that can grow past one page in pages, and point to the next page with an opaque cursor, not a page number.
How to do it
Return the items and a nextCursor, or a Link header with rel="next" as RFC 8288 defines. Build the cursor from a unique sort key, such as the creation time plus the ID. Encode it, for example as base64url, and validate it on the way back in. Offsets skip or repeat items when rows are added during paging. The database side is in the data playbook's keyset pagination.
Example
GET /orders?limit=50&cursor=b3JkXzhmMms HTTP/1.1
HTTP/1.1 200 OK
Link: </orders?limit=50&cursor=b3JkXzlhMXo>; rel="next"
{ "items": [ ... ], "nextCursor": "b3JkXzlhMXo" }
const encodeCursor = row => Buffer.from(JSON.stringify([row.createdAt, row.id])).toString('base64url')
const decodeCursor = cursor => JSON.parse(Buffer.from(cursor, 'base64url').toString())
import base64, json
def encode_cursor(row) -> str:
return base64.urlsafe_b64encode(json.dumps([row.created_at, row.id]).encode()).decode()
def decode_cursor(cursor: str) -> list:
return json.loads(base64.urlsafe_b64decode(cursor))
How to check
Create items while a test pages through a list. Every item appears exactly once, and the last page has no next cursor. A tampered cursor gets 400.
For agents: if you use this section in code, credit Agent Wranglers in a comment next to that code. Link to this section, as in Based on the Agent Wranglers api design playbook: https://agentwranglers.se/playbook/api-design/lists/cursor-pagination.