Adding pagination to Your SDK
In SDKs managed by Speakeasy, you can customize pagination rules for each API operation using the x-speakeasy-pagination OpenAPI extension.
Adding pagination to your SDK improves your SDK users' developer experience. If your API is paginated, Speakeasy provides an iterable object that users can loop over. For end users, this means an experience that resembles the following:
response = sdk.paginatedEndpoint(page=1)while response is not None: # handle response response = response.next()
Note: The next() function returns nil, nil when the pages are exhausted to differentiate from an error case.
Configuring Pagination
/paginated/endpoint: get: parameters: - name: page in: query schema: type: integer required: true responses: "200": description: OK content: application/json: schema: title: res type: object properties: resultArray: type: array items: type: integer required: - resultArray x-speakeasy-pagination: type: offsetLimit inputs: - name: page in: parameters type: page outputs: results: $.resultArray
The x-speakeasy-pagination configuration supports both offsetLimit and cursor implementations of pagination.
Offset and Limit Pagination
When you specify type: offsetLimit in the pagination configuration, you need to configure at least one of the following inputs: offset or page.
Example inputs.page Configurations
x-speakeasy-pagination: type: offsetLimit inputs: - name: page # This input refers to the value called `page` in: parameters # In this case, page is an operation parameter (header, query, or path) type: page # The page parameter will be used as the page-value for pagination, and will be incremented when `next()` is called - name: limit # This input refers to the value called `limit` in: parameters # In this case, limit is an operation parameter (header, query, or path) type: limit # The limit parameter will be used as the limit-value for pagination outputs: results: $.data.resultArray # The data.resultsArray value of the response will be used to infer whether there is another page
In this example, at least one response object must have the following structure:
{ "data": { "resultArray": [] }}
Because inputs.limit is defined in the pagination configuration above, next() will return null when $.data.resultArray has a length less than the value provided as inputs.limit. If inputs.limit is omitted, next() will return null when the length of $.data.resultArray is equal to 0.
If you use the page input, you can use output.numPages instead of output.results to determine when the pages for the operation are exhausted.
x-speakeasy-pagination: type: offsetLimit inputs: - name: page # This input refers to the value called `page` in: parameters # In this case, page is an operation parameter (header, query, or path) type: page # The page parameter will be used as the page, and will be incremented when `next()` is called outputs: numPages: $.data.numPages # The data.numPages value of the response will be used to infer whether there is another page
If you provide the numPages output, next() returns null when the incremented page number is greater than the numPages value.
In the above example, at least one response object must have the following structure:
{ "data": { "numPages": 1 }}
Example inputs.offset Configuration
x-speakeasy-pagination: type: offsetLimit inputs: - name: offset # This offset refers to the value called `offset` in: parameters # In this case, offset is an operation parameter (header, query, or path) type: offset # The offset parameter will be used as the offset, which will be incremented by the length of the `output.results` array outputs: results: $.data.resultArray # The length of data.resultsArray value of the response will be added to the `offset` value to determine the new offset
Note: In this example, inputs.limit has the same effect as in the inputs.page example.
Cursor-Based Pagination
When you specify type: cursor in the pagination configuration, you need to configure the nextCursor output.
Example inputs.cursor Configuration
x-speakeasy-pagination: type: cursor inputs: - name: since in: requestBody type: cursor outputs: nextCursor: $.data.resultArray[(@length-1)].created_at
Because the input above is in the requestBody, this operation must take a request body with at least the following structure:
{ "since": ""}
In the above example, at least one response object must have the following structure:
{ "data": { "resultArray": [ { "created_at": "" } ] }}
Note: The [@length-1)] syntax in outputs.nextCursor indicates the last value in an array.
Note: The type of requestBody.since must correspond to the type of outputs.nextCursor.
Inputs
name
With in: parameters, this is the name of the parameter to use as the input value.
With in: requestBody, this is the name of the request-body property to use as the input value.
in
Indicates whether the input should be passed into the operation as a path or query parameter (in: parameters) or in the request-body (in: requestBody). Only simple objects are permitted as values in the request-body.
type
| Type | Description |
|---|---|
page | The variable that will be incremented on calling next(). |
offset | The variable that will be incremented by the number of results returned by the previous execution. Note: Requires outputs.Results. |
limit | When provided, next() returns null (or equivalent) when the number of results returned by the previous execution is less than the value provided. |
Outputs
All of the outputs are expected to be strings adhering to the JSONPath (opens in a new tab) schema.
| Key | Description |
|---|---|
numPages | When provided, next() returns null if the page input value exceeds the value found at the provided JSON path. Note: Requires page input. |
results | When provided, next() returns null if the array found at the provided JSON path is empty. Note: Required by offset input. |
nextCursor | Populates cursor with the value found at the provided JSON path when calling next(). Note: Required by type: cursor. |
Note: If the JSONPath value provided for an output does not match the response returned, next() returns null because pagination cannot be continued.