API Pagination turns big archives of data into smaller, more digestible pieces. Clicking through an archive of pictures, or turning the page of a book, are examples of pagination. How is this important in API structure? When we use a GET API request to request information from a server via API endpoint, there could be thousands of entries in the returned JSON file. The API response sending us thousands of entries at once is a drain of resources and a waste of our time. We want to search through a database a little bit at a time, and paging helps us query databases efficiently. From the API owner's point of view, including pagination is a helpful tool to their API users, and prevents underfetching and overfetching of data. This results in less resource usage and happier API users. This guide to pagination will cover a few methods of pagination for your API.
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.
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.
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:
"tickets": [ ... ],
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.
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.
For example, /wp/v2/posts?per_page=1 will return only the first post in the collection
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.
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.