Lists and paging
Reelwire has two kinds of list, and they behave differently on purpose.
Logs never stop growing: posts, jobs, renders, ingest events, approvals, invoices. These are paged, searched and sorted by the server, over every row the workspace has.
Configuration does not grow without bound: brands, channels, streams, post lists, the media library. These come back whole, and the client searches and sorts them itself. A library is hundreds of files, not millions, and paging it would buy nothing and cost a round trip.
The log parameters
| Parameter | What it does |
|---|---|
page | Which page, from 1. Anything else is treated as 1. |
perPage | How many to a page. 1 to 200; outside that, the route's own default. |
limit | The older name for perPage, still honoured. |
q | What was typed, matched case-insensitively across the columns the row prints. At most 200 characters. |
sort | A column name the route offers. Anything else falls back to the route's default order. |
ascending | "true" or "false". Absent is the column's own default, which is newest first for a time. |
since, until | The window, as absolute instants. |
curl "http://localhost:4000/v1/jobs?page=2&perPage=25&q=bund&sort=state&ascending=true" \
-H "Authorization: Bearer rw_your_key_here"
Every log answers with the page and the counts around it:
{
"jobs": [],
"total": 7,
"all": 7,
"page": 1,
"perPage": 1,
"facets": { "state": ["COMPLETED"] }
}
| Field | What it is |
|---|---|
total | Rows matching the filters. Divide by perPage for the last page. |
all | Rows the workspace has, ignoring the filters, so you can say "7 of 412". |
page, perPage | What you actually got, after clamping. |
facets | The values each filter can usefully take. |
The default perPage differs per route, because the screens differ: 25 for /v1/jobs, 40 for
/v1/posts, 30 for /v1/render-jobs, 50 for /v1/ingest-events, 200 for /v1/approvals. Send
perPage rather than relying on any of them.
Facets are read from the rows
facets is computed from what the workspace actually holds, not from a fixed list. A filter value
that appears there is one that can return something, and a state nothing is in does not appear. Some
lists also carry labels, which maps ids in the facets to names, so a filter dropdown does not need
a second request to say "Channel 4 de" instead of a ULID.
An unparseable filter widens rather than refuses
since and until that cannot be read are ignored, not rejected. This is a filter on a list, and
the honest failure is to show more, not to show an error. The same goes for a sort column a route
does not offer, and for a filter repeated in the query string: a key given twice arrives as an
array, a filter is only ever one value, so it is treated as no filter at all.
A search longer than 200 characters is the one exception, and is a 400.
Windows mean different things
On /v1/jobs, the window is when something happened to the job: it arrived, it rendered, or one
of its posts changed. A job that arrived yesterday and published ten minutes ago is inside the last
hour, because the rows sort by Updated and anything else would be a lie.
On /v1/posts and the other logs, it is when the row was created.
/v1/calendar is not a log and takes from and to instead, both required, both absolute instants,
with a window of at most 62 days.
Paging safely while things are arriving
A log is ordered newest first, so a row arriving between two requests shifts everything down a place and page 2 can repeat a row page 1 already showed. Two ways round it:
- Pin the window. Pass
untilset to the moment you started, and page through a set that cannot grow underneath you. - Page from the oldest end, with
ascending=true, where you are reading everything rather than the most recent.
Every row carries an id, so deduplicating on the way through works whatever you do.
The lists that are not paged
/v1/brands, /v1/channels, /v1/streams, /v1/queues, /v1/media, /v1/media/renders,
/v1/feeds and /v1/templates return everything. page and perPage on them do nothing.
/v1/deliveries is in between: it is a log, but it takes limit alone, defaulting to 40 and capped
at 200, with no page.