Pagination
Read a single page from any list method, or let the SDK walk every page for you.
Every list method in @medblocks/connect is cursor-paginated. Await the call and you get one page back. Call .autoPagingIterator() on the same call and the SDK follows the cursor for you, page after page, until there is nothing left.
The two modes share one call. You choose how to consume it.
Fetch one page
Await a list call to get a single Page. It carries the items in data, a has_more flag, and a next_cursor you pass back to get the page after this one.
const page = await mb.patients.list({ limit: 50 });
for (const patient of page.data) {
console.log(patient.id);
}
if (page.has_more && page.next_cursor) {
const next = await mb.patients.list({ limit: 50, starting_after: page.next_cursor });
}A Page exposes three fields.
| Field | What it is |
|---|---|
data | The items on this page, typed to the resource you listed. |
has_more | true when at least one more page exists after this one. |
next_cursor | The cursor to pass as starting_after next time, or null at the end. |
Page is exported, so you can annotate code that receives one.
import type { Page, Patient } from "@medblocks/connect";
function firstId(page: Page<Patient>) {
return page.data[0]?.id ?? null;
}Awaiting the same list call more than once does not refetch. The SDK caches the first page on the returned value, so two awaits share one network request.
const patients = mb.patients.list({ limit: 50 });
const a = await patients;
const b = await patients;
// one request, same pagePage through everything
When you want the whole result set, call .autoPagingIterator() instead of awaiting, and drive it with for await. The SDK yields each item, then follows next_cursor to fetch the next page, and stops when has_more is false.
let count = 0;
for await (const patient of mb.patients.list({ limit: 100 }).autoPagingIterator()) {
count += 1;
}
console.log(`${count} patients total`);It works the same on every list method.
for await (const session of mb.patients.listPatientSessions("user_42").autoPagingIterator()) { /* ... */ }
for await (const source of mb.connections.list({ q: "epic" }).autoPagingIterator()) { /* ... */ }Be careful walking the whole catalog. mb.connections.list() spans every source Medblocks knows, which is large. Filter it with q or type, or page through it manually, rather than iterating all of it in one loop.
Manual cursors
.autoPagingIterator() walks everything in a single pass, which suits a script that runs start to finish. Reach for manual cursors when the job needs to survive interruptions or run in batches. Save next_cursor after each page and you can resume where you left off, across separate runs of a cron or queue worker.
The cursor is an opaque token. Store it as is and pass it back as starting_after. Do not build or parse one yourself.
let cursor: string | null = await checkpoint.read();
while (true) {
const page = await mb.patients.list({ limit: 100, starting_after: cursor ?? undefined });
for (const patient of page.data) await process(patient);
if (!page.has_more || !page.next_cursor) break;
cursor = page.next_cursor;
await checkpoint.write(cursor);
}Limits
Pass limit to set the page size. The default is small, so set it explicitly when you page through a lot of data.
| Param | Default | Range |
|---|---|---|
limit | 10 | 1 to 100 |
starting_after | none | A cursor from a previous page’s next_cursor |
A limit above 100 is rejected with a MedblocksInvalidRequestError. Some lists take extra filters on top of these, such as q and type on mb.connections.list. Each resource documents its own.
