There are a few different methods of pagination you can use depending on your API's needs. Consider how your customer will consume this data, and help them navigate it with intelligent pagination.
Offset pagination uses the `limit` and `offset` commands already present in the SQL library as query parameters. For example:`GET /paintings?offset=0&limit=10``offset` tells the server the number of items that should be skipped, while `limit` indicates the number of items to be returned. So, this will search ten paintings at a time, and skip 0 of them. One issue with this approach is the outcome if someone removes a record from the data set. This throws off your whole search, and you will miss one item.
Keyset pagination takes a cue from SQL database searching. It passes a query parameter with a timestamp to thoroughly paginate through an API call.
- The client requests most recent items with `GET /items?limit=20`
- Upon clicking the next page (first page to second page), the query finds the minimum created date of 2019â€“01â€“20T00:00:00 (the first 20 results). This is then used to create a query `limit` filter for the next page:`GET /items?limit=20&created:lte:2019-01-20T00:00:00`
This will paginate until the last page is reached.
Seek pagination returns consistent ordering even when new items are added to the table. We add `after_id` or `start_id` URL parameters.
- Client makes request for most recent items: `GET /items?limit=20`
- Upon clicking the next page, client finds the last id of â€˜20â€™ from previously returned results. and then makes second query using it as the starting id: `GET /items?limit=20&after_id=20`
- Upon clicking the next page, client finds the last id of â€˜40â€™ from previously returned results. and then makes third query using it as the starting id: `GET /items?limit=20&after_id=40`
To use cursor pagination, include the `page[size]` parameter in the request parameters. This parameter is also used to specify the number of items to return per page. Most endpoints (like Wordpress below) limit this to a maximum of 100.
A request to the `tickets` endpoint with the URL `https://example.zendesk.com/api/v2/tickets.json?page[size]=100` would return a response with the following format:
The user can use `after_cursor` and `before_cursor` properties nested in the meta JSON object to construct the URL to retrieve the next or previous page of results.
In the Wordpress documentation, Wordpress describes the pagination functionality they include in their APIs. You can imagine they deal with a great deal of API requests, and pagination of reams of blog pages would greatly increase efficiency in their use case. Their solution was to support common query parameters from requests to handle paging.
- ?page=: specify the page of results to return.
For example, /wp/v2/posts?page=2 is the second page of posts results
By retrieving /wp/v2/posts, then /wp/v2/posts?page=2, and so on, you may access every available post through the API, one page at a time.
- ?per_page=: specify the number of records to return in one request, specified as an integer from 1 to 100.
For example, /wp/v2/posts?per_page=1 will return only the first post in the collection
- ?offset=: specify an arbitrary offset at which to start retrieving posts
For example, /wp/v2/posts?offset=6 will use the default number of posts per page, but start at the 6th post in the collection
?per_page=5&page=4 is equivalent to ?per_page=5&offset=15
Wordpress also mentions that because large queries can hurt site performance, the number of results returned by `per_page` is capped at 100 records.
The API returns two header fields with every paginated response:
`X-WP-Total`: the total number of records in the collection`X-WP-TotalPages`: the total number of pages encompassing all available records
When you build your API, consider how the user might want to get data, and how your resources can handle them most efficiently, when designing pagination.
API Response Optimization
In addition to pagination, there are other sorting methods your API can use to optimize API responses and limit bloat.
The easiest way to add basic filtering to RESTful APIs is with URL parameters. If you have an `/items` endpoint which are items for sale, you can filter via the property name such as `GET /items?state=active` or `GET /items?state=active&seller_id=1234`. This only works for exact matches, we will use ranges if we want to filter a range of results.
A "range" header can be specified in the request to limit the number of items returned in a list. The header format must be as follows:
`Range: items = <start> - <end>`
<start> and <end> must be strictly positive numbers to specify the desired range of items, <start> and <end> are inclusive.
Other options for ranges include using LHS brackets with an operator: `price[lte]=200` (return results less than equal to 200) `status[ne]=past` (return results not equal to past). Operators include [regex] for [regular expressions](/what-is-regex.md) or [gte] for "greater than equal to."
To enable sorting, add a `sort` or `sort_by` URL parameter that can take a field name as the value.
However, good API designs give the flexibility to specify `ascending` or `descending` order. Like filters, specifying the order requires encoding three components into a key/value pair.
For example: `GET /users?sort_by=asc(email)` and `GET /users?sort_by=desc(email)`
When building your API, keep pagination in mind. Use common variables like `self`, `first`, `next`, and `last` that are widely used by API developers.