|
| 1 | +--- |
| 2 | +id: api-rest-pagination |
| 3 | +title: API REST Pagination |
| 4 | +sidebar_label: Pagination |
| 5 | +--- |
| 6 | + |
| 7 | +Pagination is a strategy that limits access to large datasets by dividing the data into manageable chunks or "pages." This |
| 8 | +approach provides mechanisms for accessing subsequent or previous pages of data. |
| 9 | + |
| 10 | +When dealing with API responses that could potentially return large datasets, pagination becomes essential for two main reasons: |
| 11 | + |
| 12 | +1. **Mitigate data access abuse**: Pagination limits the amount of data that can be accessed in a single request. Clients or |
| 13 | + consumers can only retrieve a defined subset of data per page, preventing potential system overload or abuse. |
| 14 | + |
| 15 | +2. **Improve response performance**: By returning smaller sets of data, pagination ensures faster response times. This is |
| 16 | + particularly beneficial when dealing with large datasets, as it reduces the load on both the server and the client. |
| 17 | + |
| 18 | +Ory supports two pagination strategies: |
| 19 | + |
| 20 | +- **Token-based pagination**: The primary and recommended method for paginating through data in Ory's API. |
| 21 | +- **Offset pagination**: A deprecated method that is still supported but not recommended for new implementations. |
| 22 | + |
| 23 | +In the following sections, we'll explore each of these pagination strategies in detail, with a focus on the recommended |
| 24 | +token-based approach. |
| 25 | + |
| 26 | +## Token pagination |
| 27 | + |
| 28 | +Ory implements token-based pagination as the primary method for handling large datasets in list operations. This approach offers |
| 29 | +better performance and consistency compared to traditional offset-based pagination. |
| 30 | + |
| 31 | + |
| 32 | + |
| 33 | +### Pagination parameters |
| 34 | + |
| 35 | +Ory uses two parameters to paginate through data: |
| 36 | + |
| 37 | +1. `page_size`: Determines the number of items returned per page. |
| 38 | +2. `page_token`: Acts as a pointer to a specific page in the dataset. |
| 39 | + |
| 40 | +### How it works |
| 41 | + |
| 42 | + |
| 43 | + |
| 44 | +Let's walk through an example to illustrate how token pagination works in Ory: |
| 45 | + |
| 46 | +Imagine you have 300 customers in your Ory project, and you want to list them 100 at a time. |
| 47 | + |
| 48 | +1. **Initial request**: Set the `page_size` query parameter to 100 for your first request: |
| 49 | + |
| 50 | + ```shell |
| 51 | + GET https://$PROJECT_SLUG.projects.oryapis.com/admin/identities?page_size=100 |
| 52 | + Authorization: Bearer $ACCESS_TOKEN |
| 53 | + ``` |
| 54 | + |
| 55 | +2. **Response**: You'll receive a response payload containing the first 100 customers. Additionally, the response header will |
| 56 | + include a `link` header with details about the first and next pages: |
| 57 | + |
| 58 | + ```shell |
| 59 | + link: |
| 60 | + </admin/identities?page_size=100&page_token=00000000-0000-0000-0000-000000000000>; rel="first", |
| 61 | + </admin/identities?page_size=100&page_token=30f8507f-40e6-44b9-924f-5f814e3f072e>; rel="next" |
| 62 | + ``` |
| 63 | + |
| 64 | +3. **Understanding the Link Header**: |
| 65 | + |
| 66 | + - The `first` link always points to the first page of results. Its token (in this case, `00000000-0000-0000-0000-000000000000`) |
| 67 | + remains constant. |
| 68 | + - The `next` link points to the next page of results. Its token (e.g., `30f8507f-40e6-44b9-924f-5f814e3f072e`) is unique and |
| 69 | + changes with each page. |
| 70 | + |
| 71 | +4. **Subsequent requests**: To retrieve the next page, use the `next` token in your follow-up request: |
| 72 | + |
| 73 | + ```shell |
| 74 | + GET https://$PROJECT_SLUG.projects.oryapis.com/admin/identities?page_size=100&page_token=30f8507f-40e6-44b9-924f-5f814e3f072e |
| 75 | + Authorization: Bearer $ACCESS_TOKEN |
| 76 | + ``` |
| 77 | + |
| 78 | +### Best practices |
| 79 | + |
| 80 | +- Always use the tokens provided in the `link` header for navigation. Do not attempt to generate or modify these tokens yourself. |
| 81 | +- If you need to start from the beginning, use the `first` link or omit the `page_token` parameter. |
| 82 | +- Keep track of the previous/current `next` token to allow for backward pagination through your results. |
| 83 | +- Be prepared for the maximum `page_size` to change. Your implementation should handle such changes gracefully. |
| 84 | +- Do not attempt to reverse engineer or make assumptions about the `page_token` format, as it may change without notice. Always |
| 85 | + treat it as an opaque string. |
| 86 | + |
| 87 | +By leveraging token-based pagination, you can efficiently navigate through large datasets in Ory, ensuring consistent and |
| 88 | +performant data retrieval. |
| 89 | + |
| 90 | +## Usage examples |
| 91 | + |
| 92 | +The following examples demonstrate how to use token-based pagination with Ory's SDKs in Python and Ruby. |
| 93 | + |
| 94 | +### Scenario 1: Python SDK |
| 95 | + |
| 96 | +This example shows how to fetch a single page of identities using the Python SDK: |
| 97 | + |
| 98 | +```python |
| 99 | +import os |
| 100 | +from pprint import pprint |
| 101 | +from ory_client.api_client import ApiClient |
| 102 | +from ory_client.configuration import Configuration |
| 103 | +from ory_client.api.identity_api import IdentityApi |
| 104 | + |
| 105 | +# Configure your Ory credentials |
| 106 | +configuration = Configuration( |
| 107 | + access_token="{API_KEY}", |
| 108 | + host="https://{PROJECT_SLUG}.projects.oryapis.com", |
| 109 | +) |
| 110 | + |
| 111 | +# Enter a context with an instance of the API client |
| 112 | +with ApiClient(configuration) as api_client: |
| 113 | + # Create an instance of the API class |
| 114 | + api_instance = IdentityApi(api_client) |
| 115 | + |
| 116 | + try: |
| 117 | + # List Identities |
| 118 | + api_response = api_instance.list_identities( |
| 119 | + page_size=1, |
| 120 | + page_token="<token>", |
| 121 | + ) |
| 122 | + pprint(api_response) |
| 123 | + except Exception as e: |
| 124 | + print("Error fetching identities: %s\n" % e) |
| 125 | +``` |
| 126 | + |
| 127 | +Key points: |
| 128 | + |
| 129 | +- Replace `{API_KEY}` with your actual Ory API key. |
| 130 | +- Replace `{PROJECT_SLUG}` with your Ory project slug. |
| 131 | +- The `page_size` is set to 1 for demonstration purposes. Adjust this value based on your needs. |
| 132 | +- Replace `<token>` with the actual page token received from a previous request, or omit it for the first request. |
| 133 | + |
| 134 | +For more details, see the |
| 135 | +[IdentityApi list documentation](https://github.com/ory/sdk/blob/master/clients/client/python/docs/IdentityApi.md#list_identities). |
| 136 | + |
| 137 | +### Scenario 2: Ruby SDK |
| 138 | + |
| 139 | +This example demonstrates how to fetch a single page of identities using the Ruby SDK: |
| 140 | + |
| 141 | +```ruby |
| 142 | +require 'ory-client' |
| 143 | + |
| 144 | +# Configure your Ory credentials |
| 145 | +OryClient.configure do |config| |
| 146 | + config.host = 'https://{PROJECT_SLUG}.projects.oryapis.com' |
| 147 | + config.access_token = '{API_KEY}' |
| 148 | +end |
| 149 | + |
| 150 | +# Create an OryClient instance |
| 151 | +api_instance = OryClient::IdentityApi.new |
| 152 | +opts = { |
| 153 | + page_size: 1, |
| 154 | + page_token: '<token>' |
| 155 | +} |
| 156 | + |
| 157 | +begin |
| 158 | + # List Identities based on pagination |
| 159 | + result = api_instance.list_identities(opts) |
| 160 | + p result |
| 161 | +rescue OryClient::ApiError => e |
| 162 | + puts "Error fetching identities: #{e}" |
| 163 | +end |
| 164 | +``` |
| 165 | + |
| 166 | +Key points: |
| 167 | + |
| 168 | +- Replace `{PROJECT_SLUG}` with your Ory project slug. |
| 169 | +- Replace `{API_KEY}` with your actual Ory API key. |
| 170 | +- The `page_size` is set to 1 for demonstration purposes. Adjust this value based on your needs. |
| 171 | +- Replace `<token>` with the actual page token received from a previous request, or omit it for the first request. |
| 172 | + |
| 173 | +For more information, refer to the |
| 174 | +[IdentityApi list documentation](https://github.com/ory/sdk/blob/master/clients/client/ruby/docs/IdentityApi.md#list_identities). |
| 175 | + |
| 176 | +## Offset pagination (Deprecated) |
| 177 | + |
| 178 | +:::caution |
| 179 | + |
| 180 | +Offset pagination is deprecated. It is strongly recommended to use Token pagination instead. |
| 181 | + |
| 182 | +::: |
| 183 | + |
| 184 | +While not recommended for new implementations, Ory still supports offset-based pagination for backwards compatibility. This method |
| 185 | +allows you to paginate through data using an offset and a page size. |
| 186 | + |
| 187 | +### How it works |
| 188 | + |
| 189 | +Offset pagination uses two query parameters: |
| 190 | + |
| 191 | +1. `per_page`: The number of items you want for each page. |
| 192 | +2. `page`: The page number you want to retrieve (starts at 0). |
| 193 | + |
| 194 | +### Example usage |
| 195 | + |
| 196 | +Let's consider a scenario where you have 300 customers and you want to retrieve customers 101 to 200: |
| 197 | + |
| 198 | +```shell |
| 199 | +GET https://{PROJECT_SLUG}.projects.oryapis.com/admin/identities?per_page=100&page=2 |
| 200 | +Authorization: Bearer {YOUR_API_KEY} |
| 201 | +``` |
| 202 | + |
| 203 | +In this example: |
| 204 | + |
| 205 | +- `per_page` is set to 100, indicating you want 100 items per page. |
| 206 | +- `page` is set to 2, which will return items 201-300. |
| 207 | + |
| 208 | +### Migrating to token pagination |
| 209 | + |
| 210 | +If you're currently using offset pagination, it's highly recommended to transition to token-based pagination. Refer to the |
| 211 | +[Token Pagination section](#token-pagination) for implementation details and best practices. |
| 212 | + |
| 213 | +## Handling pagination errors |
| 214 | + |
| 215 | +Ory typically returns a 400 Bad Request error for pagination-related issues. Here's an example of an error response when supplying |
| 216 | +an invalid token: |
| 217 | + |
| 218 | +```json |
| 219 | +{ |
| 220 | + "error": { |
| 221 | + "code": 400, |
| 222 | + "status": "Bad Request", |
| 223 | + "request": "38308051-dd5e-9f91-b053-5b32f751b281", |
| 224 | + "reason": "The page token is invalid, do not craft your own page tokens", |
| 225 | + "message": "The request was malformed or contained invalid parameters" |
| 226 | + } |
| 227 | +} |
| 228 | +``` |
| 229 | + |
| 230 | +Key fields in the error response: |
| 231 | + |
| 232 | +- `code`: The HTTP status code (e.g., 400 for Bad Request) |
| 233 | +- `status`: A text representation of the HTTP status |
| 234 | +- `request`: A unique identifier for the request, useful for troubleshooting |
| 235 | +- `reason`: A specific description of what went wrong |
| 236 | +- `message`: A general error message |
0 commit comments