Lists, filters and ordering
Every collection reads the same way. Four parameters — page_size, page_token,
order_by, filter — and one envelope, whose array is named after the collection it came
from.
Code
Two things worth knowing before you write the query. Which fields you may filter and
sort by is per resource, and the reference page for each one lists them: they are the
fields with an index behind them, so a query cannot quietly table-scan the platform. And
an unknown field is refused, not ignored — a typo comes back as an
INVALID_ARGUMENT naming the field, rather than as a full unfiltered
page that looks like an answer.
For paging, page_token is the path to take: it survives rows being inserted while you
walk. skip exists for a grid that has to jump straight to page 40, and it is capped.
8. Lists
Response shape
Code
- The array field is named exactly the collection id (AIP-132). Clients derive it from the last path segment; they do not need a per-endpoint map.
next_page_tokenis an opaque string. Empty or absent means "no more". Clients MUST NOT parse it; servers MAY encode an offset, a sort key, or a Typesense cursor in it, and MAY change that encoding without a version bump.total_sizeis the count of the whole filtered collection, not of this page.
Pagination
| Param | Type | Meaning |
|---|---|---|
page_size | int | Max results. Default 50, server max 100; a resource MAY lower its max. Over the max is clamped, not rejected. |
page_token | string | Opaque token from a previous next_page_token. |
skip | int | Results to skip before the page (AIP-158). |
skip exists because the admin grid offers direct page jumps and cannot walk
tokens to reach page 40. It is bounded (skip + page_size ≤ 10000; beyond that
is OUT_OF_RANGE) because a deep Mongo skip is a linear scan. page_token
is the path a batch consumer MUST take.
Ordering
order_by=create_time desc, title
- Comma-separated
field [asc|desc], defaultasc, at most 3 keys. - Only fields the resource declares sortable are accepted; anything else is
INVALID_ARGUMENT. A field is sortable only if it is backed by an index — this rule exists so that an admin clicking a column header cannot table-scan production. - Default order is per resource and MUST be documented and indexed. It is
create_time descunless the resource says otherwise.
Filtering
filter=is_active = true AND title:"launch"
A deliberately small subset of AIP-160:
Code
:is has: case-insensitive substring on a string, membership on an array (visible_view_ids:"68b0c1").- Only fields the resource declares filterable are accepted; anything else
is
INVALID_ARGUMENTnaming the field. Functions, wildcards and traversals into unindexed subdocuments are not supported. - A parse failure returns
INVALID_ARGUMENTwith the byte offset indetails[].field_violations[].description.
Free text has no special parameter: the client composes it, e.g.
filter=title:"foo" OR content:"foo". Ranked full-text search is
a different thing with a different backend (Typesense) and is a custom method,
not a filter (§10).