Packbase

Pagination

Load long lists in pages with cursors, offsets, and page numbers.

An API usually does not return thousands of items in one response. It returns a smaller set of items called a page. The response also contains a method to request the next page. This process is pagination.

Packbase uses different pagination methods for different resources. The inbox uses a cursor. Search uses an offset. Some endpoints return the full list.

Cursor-based pagination

The inbox uses cursor-based pagination. A cursor is a bookmark that the server returns. Do not read or change the cursor. Save the value and send it unchanged in the next request.

The first request does not require a cursor. Its response contains a cursor for the next request. The has_more Boolean shows whether another page is available.

This method lets new notifications arrive while you request older notifications.

Paginated<T> shape

import type { , Notification } from '@packbase/sdk-ts'

// Paginated<T> wraps any list response
type  = <Notification>
  • data: the items in this page.
  • has_more: true if another page is available.
  • cursor: the bookmark to pass with the next request.
  • total_count: the total number of matching items, when the endpoint provides it.

Example: fetch all inbox notifications

async function () {
  const  = []
  let : string | undefined

  let  = true
  do {
    const page = await ..({ : 50,  })
const page: Paginated<Notification>
.(....) = . = . } while () return }

The loop always makes one request. After each response, it saves the cursor and checks has_more. A large inbox can cause this loop to make many requests. For a large inbox, use a “Load more” button.

Pack members are not paginated

Not every list requires a pagination loop. The pack members endpoint returns one full array:

async function (: string) {
  return .().()
}

"Load more" UI pattern

For a button interface, keep the loaded items, latest cursor, and hasMore value in the application state. This example omits framework-specific state code:

async function () {
  const page = await ..({ : 20,  })
const page: Paginated<Notification>
= [..., ....] = . = . }

Call loadMore() once for the first page and again whenever the user asks for more. Disable or hide the button when hasMore becomes false.

Offset pagination with the search builder

Search uses offset-based pagination. An offset is the number of matching items to omit. .take(25).skip(0) requests the first 25 items. .take(25).skip(25) requests the next 25 items.

Calculate these numbers with .skip() and .take(). Alternatively, use .page():

// Page 1 (items 0-24)
const  = ('packs').('created_at').(25).(0).()

// Page 2 (items 25-49)
const  = ('packs').('created_at').(25).(25).()

// Or use the helper (1-indexed)
const  = ('packs').('created_at').(3, 25).()
// Equivalent: take(25).skip(50)

You can request multiple pages at the same time with Promise.all(). Most interfaces request a page only when it is necessary:

const [{  }, {  }] = await .([
  .({ : ('packs').(1, 20).() }),
  .({ : ('packs').(2, 20).() }),
])

Select the pagination method

The endpoint specifies the pagination method. Examine the return value and use the applicable continuation value:

ResourceStrategyKey
InboxCursorcursor + has_more
Pack membersFull listNo pagination options
SearchOffset.skip() / .page()

On this page