Skip to main content

Connections and Pagination

A connection is a collection of objects that lets you paginate through it, and like other types in a GraphQL API, control exactly what data you want to receive. When you request a connection field, you can specify how many results you want, where the page should start, and (depending on the type of connection) much, much more. When you get a connection back, you'll receive a page of results with metadata for determining your place in the list and moving through it.

Connections are used in the API chiefly for search results and ownership relationships—for instance, all payment methods belonging to a given customer—but can be for any linked set of objects of a particular type or union.

If you've used connections from other GraphQL APIs, the Braintree API's implementation of connections will be familiar. It adheres to the Relay specification.

The Contents of a Connection

There are different connection types depending on what they are a collection of, but all connections follow this general structure:

genericConnection {
  edges {
    node {
      # the objects themselves
    }
    cursor
  }
  pageInfo {
    hasNextPage
  }
}

and requesting a connection field returns something like this:

{
  "genericConnection": {
    "edges": [
      {
        "node": {
          "id": "id-for-first-object-in-page",
          # ...other requested fields for this object type
        },
        "cursor": "opaque-string-for-first-object"
      },
      {
        "node": {
          "id": "id-for-second-object-in-page",
          # ...other requested fields for this object type
        },
        "cursor": "opaque-string-for-second-object"
      },
      # ...additional elements in page
    ],
    "pageInfo": {
      "hasNextPage": "true"
    }
  }
}

The edges list makes up a page's worth of objects; the list of edges is one page of results. Each edge holds a single element in the results, and contains a node (the object itself) and a cursor, which is an opaque string denoting that edge's place in the larger set of results.

You can think of "node" here as meaning the same thing as it does in a node query: a fetchable object with a unique ID. However, unlike the node query, in most cases, the field will specify what type its node objects are.

The hasNextPage boolean tells you whether there are more results—more edges—in the connection than were returned in the current page.

Simple Use

If you don't care about moving through the full list of results, and only want a subset, you can omit the optional fields used for pagination.

query Search($txnCriteria: TransactionSearchInput!) {
  search {
    transactions(input: $txnCriteria) {
      edges {
        node {
          id
          # ...all desired transaction fields
        }
      }
    }
  }
}

That query would yield the following result:

{
  "data": {
    "search": {
      "transactions": {
        "edges": [
          {
            "node": {
              "id": "transaction-id",
              # ...all desired transaction fields
            },
            "node": {
              "id": "another-transation-id",
              # ...all desired transaction fields
            },
            # up to forty-nine more transactions meeting the search criteria
          }
        ]
      }
    }
  }
}

Complex Connections

When requesting a connection field, you can provide arguments to more finely control the results you get back.

You can slice, and request only a certain number of items:

paymentMethods(first: 5) {
  edges {
    node
  }
}

You can paginate, and request items only after a certain point:

paymentMethods(after: "opaque-cursor-from-an-edge-on-a-previous-page") {
  edges {
    node
    cursor
  }
}

You can do both, and select the next x items after a certain point:

paymentMethods(first: 20, after: "opaque-cursor-from-an-edge-on-a-previous-page") {
  edges {
    node
    cursor
  }
  pageInfo {
    hasNextPage
  }
}

For some connections, you can also add in criteria determining which items are selected and what order they will appear in.

Pagination

Here is a complete example of searching with pagination:

query InitialSearch($txnCriteria: TransactionSearchInput!) {
  search {
    transactions(input: $txnCriteria, first: 20) {
      edges {
        node {
          id
        }
        cursor
      }
      pageInfo {
        hasNextPage
      }
    }
  }
}

This query will return the twenty most recently created transactions that meet the input search criteria as nodes, each wrapped in an edge, with a cursor marking its place in the full result set. The pageInfo field will indicate whether there are more than twenty transactions that meet your search criteria.

{
  "data": {
    "search": {
      "transactions": {
        "edges": [
          # ...19 prior nodes...
          {
            "node": {
              "id": "transaction-id-for-last-result-in-list"
            },
            "cursor": "cursor-for-last-transaction-in-list"
          }
        ],
        "pageInfo": {
          "hasNextPage": true
        }
      }
    }
  }
}

In order to obtain the next page in the results—or to get any new set of subsequent results after a particular node in the list—perform a second search, adding the appropriate cursor to your input.

query SecondSearch($txnCriteria: TransactionSearchInput!) {
  search {
    transactions(input:$txnCriteria, first: 20, after: "cursor-for-last-transaction-in-list") {
      # ...
    }
  }
}

This will return twenty different transactions that meet your search criteria: the next twenty created subsequent to the transaction indicated by "cursor-for-last-transaction-in-list".

When hasNextPage is false, then there are no more objects that meet your search criteria, and the last element in the current list is the oldest object in your result set.

More on Relay

For more information on the Relay specifications, including connections, edges, and cursors, here are some good resources:

icon

Cookies help customize Braintree for you, and some are necessary to make our site work. By using Braintree, you accept our use of cookies. Learn more about the cookies we use and how you can manage them.