← Docs

Pagination

How the x-pagination OpenAPI extension gives your generated SDK an async iterator over every page of a list operation.

x-pagination is a vendor extension you add to an operation in your OpenAPI document. It tells CodeForge how to walk every page of a cursor- or offset-paginated list. When an operation declares it, the generated SDK gets a second method next to the normal one: <operationId>All(), an async iterator over every item across every page.

OpenAPI has no built-in way to describe pagination, so you declare it explicitly. There is no heuristic detection — an operation only gets an iterator when you ask for one.

Declaring it

Add x-pagination under the operation, next to operationId:

get:
  operationId: listSessions
  x-pagination:
    style: cursor # or: offset
    input:
      cursor: cursor # query parameter receiving the cursor (cursor style)
      offset: offset # query parameter receiving the offset (offset style)
      limit: limit # optional, both styles: page-size query parameter
    output:
      items: data # dot.path to the items array in the JSON success response
      nextCursor: meta.next # dot.path to the next cursor (cursor style only)

style is either cursor or offset:

  • cursor — the server hands back a token in each response (output.nextCursor) that you send back as the next request's cursor (input.cursor).
  • offset — you advance a numeric offset (input.offset) yourself, by the number of items the previous page returned.

Both styles accept an optional input.limit, naming the query parameter that caps page size.

output.items is a dot-path into the operation's 2xx JSON response body, pointing at the array of items to yield. output.nextCursor is a dot-path to the next cursor, and only applies to the cursor style.

Validation

CodeForge validates every x-pagination declaration at generation time, before it emits any code. A declaration fails the whole generation run when:

  • style is anything other than cursor or offset.
  • Any named input field (cursor, offset, or limit) does not name a query parameter actually declared on the operation.
  • output.items does not resolve to an array in the operation's 2xx JSON response schema.
  • output.nextCursor is missing for cursor style, or set for offset style.
  • The operation streams (text/event-stream) — pagination and streaming are structurally incompatible.

Every failure names the operation and the offending field, so you can find and fix it in your document. The error surfaces in your generation run's logs, the same place every other generation error shows up.

The generated iterator

Alongside the normal, single-page method, the generated client exposes <operationId>All(context), returning AsyncGenerator<Item> where Item is the element type of the items array. Iterate it with for await:

for await (const item of client.listSessionsAll({ parameters: {} })) {
  console.log(item)
}

Each page goes through the same request path as the single-page call: authentication, retries, the per-attempt timeoutMs, and your configured hooks all apply. Passing a signal in the call context aborts the iteration — the in-flight request aborts, and the generator stops.

The iterator stops on its own:

  • Cursor style — when the next cursor is null, undefined, or an empty string, or when the server repeats the previous cursor (a loop guard, so a misbehaving server can never make the iterator run forever).
  • Offset style — when a page returns zero items, or fewer items than the requested limit (when you passed one).

If a page request fails after its retries, the error propagates out of the iterator — pagination never silently swallows a failure.

The single-page method is unchanged; <operationId>All() is purely additive.