# Pagination

## Overview

The Finale GraphQL API uses **cursor-based pagination** following the Relay connection specification. This provides efficient navigation through large datasets.

## Pagination Arguments

All ViewConnection queries support these arguments:

- `first: Int` \- Return the first N items
- `last: Int` \- Return the last N items
- `after: String` \- Return items after this cursor
- `before: String` \- Return items before this cursor

## PageInfo Object

Every ViewConnection returns a `pageInfo` object with:

```graphql
pageInfo {
  hasNextPage      # Boolean: Are there more items after this page?
  hasPreviousPage  # Boolean: Are there items before this page?
  startCursor      # String: Cursor for first item in results
  endCursor        # String: Cursor for last item in results
}
```

## Forward Pagination Pattern

To paginate forward through results:

```graphql
# Page 1
query {
  orderViewConnection(first: 50) {
    edges {
      node {
        orderId
        orderDate
      }
    }
    pageInfo {
      hasNextPage
      endCursor
    }
  }
}

# Page 2 - Use endCursor from previous page
query {
  orderViewConnection(first: 50, after: "cursor-value-from-page-1") {
    edges {
      node {
        orderId
        orderDate
      }
    }
    pageInfo {
      hasNextPage
      endCursor
    }
  }
}
```

## Backward Pagination Pattern

To paginate backward:

```graphql
query {
  orderViewConnection(last: 50, before: "cursor-value") {
    edges {
      node {
        orderId
        orderDate
      }
    }
    pageInfo {
      hasPreviousPage
      startCursor
    }
  }
}
```

## Cursor Format

Cursors are opaque strings that encode pagination position. They are:

- Base64-encoded JSON objects
- Should be treated as opaque by clients
- Valid only within the same query context
- Not guaranteed to be stable across different queries

**Example cursor value:**`eyJpZHgiOjEwfQ==`

## Best Practices

1. **Always check `hasNextPage`** before requesting more pages
2. **Store cursors** from `pageInfo` to navigate between pages
3. **Use consistent page size** for predictable performance
4. **Don't decode cursors** \- treat them as opaque strings
5. **Combine with sorting** for predictable pagination order

## Complete Example

```graphql
query GetProducts($cursor: String) {
  productViewConnection(
    first: 100
    after: $cursor
    sort: [{ field: "productId", mode: "asc" }]
  ) {
    edges {
      node {
        productId
        sku
        description
      }
    }
    pageInfo {
      hasNextPage
      endCursor
    }
  }
}
```
