Modulify

Pagination

How methods that return long lists hand them over a page at a time, and how to walk every page.

On this page

Methods that list things return a fixed number of items per call. Each method's page says how many and which of the patterns below it uses. There are four.

Offset and count

Most lists take an offset, the number of items to skip, and answer with count, the total. Start at 0 and add the page size until you have collected count items.

curl -X POST https://api.modulify.ai/v1/list_sites \
  -H "Authorization: Bearer YOUR_TOKEN" \
  -d '{"workspaceId":"WORKSPACE_ID","offset":8}'

list_sites, list_templates and list_deployments work this way. A few, such as list_rows, list_workspace_members and get_publish_logs, also take a limit for the page size, up to a maximum their page states. Some answer with hasMore and the offset to send next instead of a total, such as list_workspace_credit_activity, so keep going while hasMore is true.

const ListAllSites = async (workspaceId) => {
    const sites = []

    while (true) {
        const response = await fetch('https://api.modulify.ai/v1/list_sites', {
            method: 'POST',
            headers: { Authorization: `Bearer ${process.env.MODULIFY_TOKEN}` },
            body: JSON.stringify({ workspaceId, offset: sites.length })
        })

        const result = await response.json()

        if (!result.success) throw new Error(result.message)

        sites.push(...result.data)

        if (result.data.length === 0 || sites.length >= result.count) return sites
    }
}

Next cursor

Logs and histories that grow all the time answer with a nextCursor. Send it back as cursor for the next page, and stop when it comes back null. Keep every other argument the same between pages, since the cursor belongs to that exact query.

list_deploy_hook_calls, list_site_cron_runs, list_webhook_deliveries, list_site_email_sends, list_site_email_engagement and list_site_email_suppressions work this way.

curl -X POST https://api.modulify.ai/v1/list_site_cron_runs \
  -H "Authorization: Bearer YOUR_TOKEN" \
  -d '{"projectId":"SITE_ID","cursor":"NEXT_CURSOR"}'

list_storage_files follows the same idea with a different name: it answers with nextToken, which you send back as token to read the next page of the same folder.

Page numbers

The backup histories, list_code_backups, list_storage_backups and list_database_backups, take a page that starts at 1.

Reading backwards

Two methods page through something that only grows, from the newest end:

  • list_messages returns the newest chat messages with hasMore and oldestCursor. Send oldestCursor back as cursor to get the page before, and stop when hasMore is false.
  • get_job returns the events of a generation after a numeric cursor. Send back the cursor from each answer to receive only new events. See Long-running work.

Tips

  • Read count, not the page length. The last page is usually shorter than the rest, and an empty page means you have read everything.
  • Expect change while you page. Items added or removed between two calls can shift an offset by one. For a stable copy of one collection, export_collection returns its rows in a single call.
  • Pace yourself. Every page is one call against the token's per-minute budget. See Rate limits.

Next