> ## Documentation Index
> Fetch the complete documentation index at: https://www.propeldata.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Pagination

> Cursor-based pagination with GraphQL.

<div />

Throughout the Propel API, you'll encounter collections of items: lists of Applications, Data Sources, Data Pools, and Metrics, for example. Rather than give you every item in the collection — which could be prohibitively large — the Propel API returns them to you in parts called "pages".

The Propel GraphQL APIs uses "cursors" for accessing these pages: when fetching a collection, the initial set of results arrives in a page containing "forward" and "backward" cursors. You can access the next page of results by following the forward cursor, and you can access the previous page of results by following the backward cursor. This is how user interfaces featuring "next page" and "previous page" buttons are typically implemented.

This guide explains the mechanics of cursor-based pagination and how Propel GraphQL APIs use it.

* [Cursor-based pagination overview](#cursor-based-pagination-overview)
* [The request parameters](#the-request-parameters)
* [The PageInfo response object](#the-pageinfo-response-object)
* [GraphQL API pagination](#graphql-api-pagination)

## Cursor-based pagination overview

Cursor-based pagination works by requesting some number of items before or after a particular item (the cursor) in a collection. The API returns the fetched items and a new pair of cursors pointing to the first and last items of the results. Your application can then use these new cursors in subsequent requests to page forward or backward through the items, always fetching the next page before or the next item after the first and last items in the current page, respectively.

### Key terminology

* **Your application** - The web or mobile application you are building.
* **Cursor** - A pointer to an individual item in a collection.

```mermaid theme={"system"}
sequenceDiagram
    Your Application->>+Propel API: query dataSources (first: 10 )
    Propel API->>-Your Application: Returns 10 Data Sources and endCursor=ABC123
    Your Application->>+Propel API: query dataSources (first: 10 after:ABC123 )
    Propel API->>-Your Application: Returns the next 10 Data Sources.
```

1. Your application makes an initial request with a parameter indicating the number of items it wants per page, 10, for example.
2. The Propel API responds with the items if they exist and a pagination object (PageInfo) that contains a cursor to the first and last item of the results and whether a next or previous page exists.
3. To see the next items, your application makes another API request indicating the number of items to fetch and the cursor to the next page.
4. The Propel API fetches the next 10 items after the cursor and returns them to your application.

## The request parameters

The Propel API expects the following parameters when making requests that fetch collections of items in list-style queries in GraphQL (`dataSources`, `dataPools`, `metrics`, and `applications`).

To page forward, the `first` and `after` parameters are expected:

| Parameter | Description                                                                                                                               |   Default   | Maximun | Required |
| :-------- | :---------------------------------------------------------------------------------------------------------------------------------------- | :---------: | :-----: | :------: |
| first     | Indicates the number of items to be returned.                                                                                             |      10     |   100   |    No    |
| after     | The cursor that indicates the position where to start fetching items forward. The result will not include the item in the `after` cursor. | most recent |    --   |    No    |

To page backward, the `last` and `before` parameters are expected:

| Parameter | Description                                                                                                                                 |   Default   | Maximun | Required |
| :-------- | :------------------------------------------------------------------------------------------------------------------------------------------ | :---------: | :-----: | :------: |
| last      | Indicates the number of items to be returned.                                                                                               |      10     |   100   |    No    |
| before    | The cursor that indicates the position where to start fetching items backward. The result will not include the item in the `before` cursor. | most recent |    —    |    No    |

All parameters are optional. Below is the Propel API behavior for each case.

* If **no** parameters are provided, the most recent 10 items will be returned.
* If **all** parameters are provided, a 400 Bad Request is returned.
* If **only** `first` is provided, the most recent specified number of items will be returned.
* If **only** `last` is provided, an empty list is returned.
* If **only** `after` or `before` are provided, the default count of items before or after the cursor will be returned.
* If **both** `after` and `before` are provided, a 400 Bad Request is returned.
* If **only** `first` and `before` are provided, a 400 Bad Request is returned.
* If **only** `last` and `after` are provided, a 400 Bad Request is returned.

## The `PageInfo` response object

Every API response to requests fetching collections of items like list queries in GraphQL (`dataSources`, `dataPools`, `metrics`, and `applications`) will return a `PageInfo` object.

The PageInfo object has the following properties:

* **startCursor** - Points to the first item returned in the results. Used when paginating backward.
* **endCursor** - Points to the last item returned in the results. Used when paginating forward.
* **hasNextPage** - A boolean that indicates whether a next page exist. Used to know whether to display a "Next page" UI button.
* **hasPreviousPage** - A boolean that indicates whether a previous page exist. Used to know whether to display a "Previous page" UI button.

### A note about cursors

Cursors are opaque strings that contain the necessary information to locate the next (or previous) page of results. Your application doesn't need to know the format of the cursor — just pass the cursor string along to Propel, and we'll figure out the rest.

## GraphQL API pagination

Propel's GraphQL cursor-based pagination is based on the <a href="https://relay.dev/graphql/connections.htm" target="_blank">Relay Cursor Connections Specification</a>. Apollo has a great in-depth post, <a href="https://www.apollographql.com/blog/graphql/explaining-graphql-connections/" target="_blank">"Explaining GraphQL Connections"</a>, that we recommend if the concept of GraphQL connections is new to you.

The key thing to note is that, in addition to the parameters and `pageInfo` response object described above, GraphQL cursor-based pagination makes use of Connections and Edges.

* **Connections** - A wrapper object that contains the details of the list you are paging through. A connection has two properties: `edges` and `pageInfo`. The property `pageInfo` is an instance of the `PageInfo` object described above.

* **Edge** - A wrapper around an individual item in the result set that includes the item and a cursor that points to it.

The wrapper objects are a standardized way to include the `cursor` value when returning an object and the `pageInfo` object when returning the list without changing the base objects.

Let's look at an example of how these objects look like in the Metrics GraphQL Schema.

A Metric connection has the `pageInfo` object and a `MetricEdge` array.

```graphql theme={"system"}
type MetricConnection {
  pageInfo: PageInfo!
  edges: [MetricEdge!]
}
```

The Metric Edge has the `cursor` and the actual `Metric` object.

```graphql theme={"system"}
type MetricEdge {
  cursor: String!
  node: Metric!
}
```

In its simplest invocation, the `getAllMetrics` query would be called with either `first` and `after` or `last` and `before` and would return a `MetricsConnection`.

```graphql theme={"system"}
getAllMetrics(
		first: Int
		after: String
		last: Int
		before: String
		): MetricsConnection
```

### Example getAllMetrics request

This example illustrates how to fetch the 50 most recently created Metrics across two pages of 25 Metrics each.

First we fetch the 25 most recently created Metrics, setting `first` to 25 in our query. This will return the first page of results. Make sure to request `pageInfo` and `edges` to be included in the response.

```graphql theme={"system"}
Query getAllMetrics {
	getAllMetrics(first: 25){
        pageInfo
        edges
    }
}
```

The response arrives as a MetricConnection object representing the first page of results:

```graphql theme={"system"}
{
  "data":{
    "metrics": {
        "pageInfo": {
            "startCursor": "YWNjb3VudElkOkFDVDAxQVJaM05ERUtUU1Y0UlJGRlE2OUc1RkFW",
            "endCursor": "YWNjb3VudElkOkFDVDAxQVJaM05ERUtUU1Y0UlJGRlE2OUc1RllI",
            "hasNextPage": true,
            "hasPreviousPage": false
        },
        "edges": [{
            "cursor":"YWNjb3VudElkOkFDVDAxQVJaM05ERUtUU1Y0UlJGRlE2OUc1RkFW",
            "node": {
                "id": "MET01ARZ3NDEKTSV4RRFFQ69G5FAV",
                ... all other Metric properties ...
            }
        },
        ... all other 23 edges ..
        {
            "cursor":"YWNjb3VudElkOkFDVDAxQVJaM05ERUtUU1Y0UlJGRlE2OUc1RllI",
            "node": {
                "id": "MET04AZ3NDEKTSV4R5FAVRRFFQ69G",
                ... all other Metric properties ...
            }
        }]
    }
}
```

Now, we want to fetch the next 25 Metrics. To do so, we make another query setting `first` to 25 and `after` to the value of the `endCursor` we got in the MetricsConnection response. This will return the second page of results.

```graphql theme={"system"}
Query metrics {
	getAllMetrics(first: 25, after: 'YWNjb3VudElkOkFDVDAxQVJaM05ERUtUU1Y0UlJGRlE2OUc1RllI'){
        pageInfo
        edges
    }
}
```

This will return the next 25 metrics if they exist.

***Happy pagination!***
