Skip to content
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
178 changes: 86 additions & 92 deletions fern/products/sdks/guides/configure-auto-pagination.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -3,105 +3,30 @@ title: Configure Auto Pagination
description: Paginate through API responses easily with offset, cursor, and link-based pagination.
---

<Markdown src="/snippets/pro-callout.mdx" />
Fern's auto pagination supports offset-based and cursor-based pagination schemes,
providing SDK users with simple iterators to loop through all results instead of
managing pagination complexity manually.

Instead of forcing SDK users to learn the intricacies of your pagination system, Fern SDKs will return an iterator so that users can simply loop through all the results.
This page describes how to configure auto pagination for your API endpoints.

<Tabs>
<Tab title="TypeScript" language="typescript">

When pagination for an endpoint is configured, the TypeScript SDK method
will return a `Page<T>` where `T` is the underlying data type. The `Page<T>`
will implement the `AsyncIterable` interface, allowing you to use it in a
`for await` loop.

Below is an example method signature for a list endpoint:
```typescript UsersClient.ts {10-13}
import core from "../core";

export interface UsersClient {

/**
* List all users
* @param props
* @returns A page of users
*/
list(
request: ListUsersRequest = {},
requestOptions: core.RequestOptions = {}
): core.Page<User>;
}
```

And here is an example of how a user would use the `list` method:
```typescript
const response = await client.users.list();
for await (const user of response) {
console.log(user);
}
```

</Tab>
<Tab title="Python" language="python">

When pagination for an endpoint is configured, the Python SDK method
will return a `Pager[T]` (specifically a `SyncPager[T]` or an `AsyncPager[T]`) where `T` is the underlying data type. The `Pager[T]`
will implement the `Generator` interface, allowing you to use it in a
`for ... in` loop.

Below is an example method signature for a list endpoint:
```python client.py {3-9}
class UsersClient:

def list_with_cursor_pagination(
self,
*,
page: typing.Optional[int] = None,
page_size: typing.Optional[int] = None,
request_options: typing.Optional[RequestOptions] = None,
) -> SyncPager[User]:
...
```

And here is an example of how a user would use the `list` method:
```python
for user in client.users.list(page=1, page_size=10):
print(user)
```

or if the user is leveraging the asynchronous client:
```python
async for user in await client.users.list(page=1, page_size=10):
print(user)
```
</Tab>
</Tabs>

### Supported pagination types

Fern supports the following pagination schemes:
## Setting up auto pagination

| Pagination Scheme | Supported |
|-------------------|--------------------------------------------------|
| Offset-based | <Icon icon="check" color="#84B060" /> |
| Cursor-based | <Icon icon="check" color="#84B060" /> |
| Link-based | |
To configure auto pagination, specify the dot-access path to the related request
or response property in the `x-fern-pagination extension` (OpenAPI) or `pagination`
field (Fern Definition).

#### Configuration
For example, if results of `my_nested_object` are located in the subfield
`inner_list`, the dot-access path would be `results:
$response.my_nested_object.inner_list`.

Annotate the desired paginated endpoint with the `x-fern-pagination` extension.
For these fields, you can simply specify the dot-access path to the related request or response property.

For example, should the results of the following object be found in the subfield `inner_list`, you would specify `results: $response.my_nested_object.inner_list`.

```yaml
```yaml {7-10}
MyResponseObject:
type: object
properties:
my_nested_object:
type: object
properties:
inner_list:
inner_list: # location of results
type: array
items:
$ref: '#/components/schemas/MyObject'
Expand All @@ -111,7 +36,7 @@ MyResponseObject:
<Tabs>
<Tab title="OpenAPI">
<CodeBlocks>
```yaml Offset
```yaml Offset {6}
...
paths:
/path/to/my/endpoint:
Expand All @@ -121,7 +46,7 @@ paths:
...
```

```yaml Cursor
```yaml Cursor {8}
...
paths:
/path/to/my/endpoint:
Expand All @@ -138,7 +63,7 @@ paths:
<Tab title="Fern Definition">
<CodeBlocks>

```yaml Offset
```yaml Offset {6}
service:
endpoints:
listWithOffsetPagination:
Expand All @@ -147,7 +72,7 @@ service:
results: $response.data
```

```yaml Cursor
```yaml Cursor {7}
service:
endpoints:
listWithCursorPagination:
Expand All @@ -161,5 +86,74 @@ service:
</Tab>
</Tabs>

## Generated SDK Usage
<Tabs>
<Tab title="TypeScript" language="typescript">

Once you've configured pagination for an endpoint, Fern generates a TypeScript
SDK method that returns a `Page<T>` where `T` is the underlying data type. The
`Page<T>` will implement the `AsyncIterable` interface, allowing your users to
use it in a `for await` loop.

Example generated method signature:
```typescript UsersClient.ts {10-13}
import core from "../core";

export interface UsersClient {

/**
* List all users
* @param props
* @returns A page of users
*/
list(
request: ListUsersRequest = {},
requestOptions: core.RequestOptions = {}
): core.Page<User>;
}
```

Example of how users would call the `list` method:
```typescript
const response = await client.users.list();
for await (const user of response) {
console.log(user);
}
```

</Tab>
<Tab title="Python" language="python">

Once you've configured pagination for an endpoint, Fern generates a Python SDK
method that returns a `Pager[T]` where `T` is the underlying data type. The
`Pager[T]` will implement the `Generator` interface, allowing your users to
use it in a `for ... in` loop.

Example generated method signature:
```python client.py {3-9}
class UsersClient:

def list_with_cursor_pagination(
self,
*,
page: typing.Optional[int] = None,
page_size: typing.Optional[int] = None,
request_options: typing.Optional[RequestOptions] = None,
) -> SyncPager[User]:
...
```

Example of how users would call the `list` method:
```python
for user in client.users.list(page=1, page_size=10):
print(user)
```

or if the user is leveraging the asynchronous client:
```python
async for user in await client.users.list(page=1, page_size=10):
print(user)
```
</Tab>
</Tabs>