Searching for Objects
A node query can fetch information about a
specific object given an ID, but if you want to fetch information about multiple objects of the
same type, you can specify criteria in a search
query. The
search
query returns the
fields you can use to search for objects. The available types you can search for are defined in
the Search
type.
Here's a typical search workflow:
-
Specify the type of object to search and the fields you want back in the
query
. - Specify your search criteria in the
variables
. - POST to the GraphQL endpoint.
- Paginate through your results.
Here's an example transaction search:
- CURL
curl \
-H 'Content-Type: application/json' \
-H 'Authorization: Basic BASE64_ENCODED(PUBLIC_KEY:PRIVATE_KEY)' \
-H 'Braintree-Version: 2019-01-01' \
-X POST https://payments.sandbox.braintree-api.com/graphql \
-d '{
"query": "query Search($input: TransactionSearchInput!) {
search { transactions(input: $input) {
pageInfo {
hasNextPage
startCursor
endCursor
},
edges {
node {
id
status
amount {
value
currencyIsoCode
}
}
}
}
}
}",
"variables": {
"input": {
"amount": {
"value": {
"greaterThanOrEqualTo": "10.00"
}
},
"status": {
"in": ["SETTLED", "VOIDED"]
}
}
}
}'
Constructing Searches
To construct a search query, first select the
type you'd like to search for, request
the fields you want to be returned in the node
field, request
pageInfo
which allows you to
paginate through your results, and then specify the
search criteria.
Search criteria are specified through input fields and generally follow one of four patterns to
specify the criteria by which you would like to filter the results of your search. If you specify
multiple criteria, they are logically AND
'd together, so all criteria must be met in
order for the search to match an object.
Searching for empty strings, null values, or empty lists is the same as omitting the search field altogether.
Ranges
Range searches support the operators is
, greaterThanOrEqualTo
, and
lessThanOrEqualTo
. The
SearchRangeInput
type is an example of the range criteria.
To specify transactions with 10.00 <= amount <= 1000.00
pass the following
input:
- Variables
{
"variables": {
"input": {
"amount": {
"value": {
"greaterThanOrEqualTo": "10.00",
"lessThanOrEqualTo": "1000.00"
}
}
}
}
}
Timestamps
Timestamp searches support the operators greaterThanOrEqualTo
and
lessThanOrEqualTo
. The
SearchTimestampInput
type is an example of the timestamp criteria.
The following would look for objects created between January 1, 2019, 6am UTC and January 3, 4pm UTC:
- Variables
{
"variables": {
"input": {
"createdAt": {
"lessThanOrEqualTo": "2019-01-03T16:00:00+00:00",
"greaterThanOrEqualTo": "2019-01-01T06:00:00+00:00"
}
}
}
}
Multiple Value Fields
Fields that accept multiple values support the operator in
. The
SearchValueInput
,
SearchTransactionStatusInput
, and
SearchDisputeTypeInput
types are all examples of the multiple value field criteria.
For example, to search for transactions that have a status of either SETTLED
orVOIDED
you could pass the following input to the search query:
- Variables
{ "variables": { "input": { "status": { "in": ["SETTLED", "VOIDED"] } } } }
Free Text Searches
Free text searches support the operators is
, isNot
,
startsWith
, endsWith
, and contains
. The
SearchTextInput
type is an example of a free text search criteria.
For example, the following input could be provided to find customers whose first name starts with
"Jo"
:
- Variables
{ "variables": { "input": { "firstName": { "startsWith": "Jo" } } } }
Note regarding isNot
: An empty string or null value for isNot
is
equivalent to omitting the field altogether. It will not search for all results where the
criteria is not null/empty.
Putting it all together
If you wanted to search for all transactions in February, 2019, greater than $100, that are
SETTLED
and have an orderId starting with "cat-food":
- CURL
curl \
-H 'Content-Type: application/json' \
-H 'Authorization: Basic BASE64_ENCODED(PUBLIC_KEY:PRIVATE_KEY)' \
-H 'Braintree-Version: 2019-01-01' \
-X POST https://payments.sandbox.braintree-api.com/graphql \
-d '{
"query": "query Search($input: TransactionSearchInput!) {
search {
transactions(input: $input) {
pageInfo {
hasNextPage
startCursor
endCursor
},
edges {
node {
id
status
amount {
value
currencyIsoCode
}
orderId
}
}
}
}
}",
"variables": {
"input": {
"createdAt": {
"greaterThanOrEqualTo": "2019-02-01T00:00:00+00:00",
"lessThanOrEqualTo": "2019-03-01T00:00:00+00:00"
},
"amount": {
"value": {
"greaterThanOrEqualTo": "100.00"
}
},
"status": {
"in": ["SETTLED"]
},
"orderId": {
"startsWith": "cat-food"
}
}
}
}'
Understanding Your Results
Braintree's GraphQL API implements the Relay Cursor Connections Specification for presenting paginated search results. To read more about how connections are used throughout our API, see the Pagination and Relay Connections guide. Relay uses cursors for managing pagination, you must use a returned cursor as a parameter to access the next page of results, all of which will be logically after the cursor provided.
Here's a query to get back your transactions without any filtering (search criteria). By default, the API returns the maximum results per page, 50. Here, we've asked for just the first three results, and only the ID and transaction status:
- GraphQL
query {
search {
transactions(input: {}, first: 3) {
pageInfo {
hasNextPage
startCursor
endCursor
}
edges {
cursor
node {
id
status
}
}
}
}
}
The server responds:
- Response
{
"data": {
"search": {
"transactions": {
"pageInfo": {
"hasNextPage": true,
"startCursor": "MTktMTAtMDhUMjA6MTA6MzRa",
"endCursor": "MTktMDktMjNUMTM6NTE6MDNa"
},
"edges": [
{
"cursor": "MTktMTAtMDhUMjA6MTA6MzRa",
"node": { "id": "dHJhbnNhY3Rpb25fZzN5Z2NmM2c", "status": "SETTLED" }
},
{
"cursor": "MTktMDktMjNUMTM6NTc6NDha",
"node": { "id": "dHJhbnNhY3Rpb25fZ2VoMnY2dmc", "status": "SETTLED" }
},
{
"cursor": "MTktMDktMjNUMTM6NTE6MDNa",
"node": { "id": "dHJhbnNhY3Rpb25fZDFuZDVhdzM", "status": "SETTLED" }
}
]
}
}
},
"extensions": { "requestId": "D48-CkB2SQkhnw==" }
}
The objects you've searched for are contained in the list edges
. Each
edge
is a node
of the data we requested (ID and status) and a cursor
representing that node
's position in the edges
list. In
pageInfo
, the startCursor
is the same as the cursor for the first
result, the endCursor
is the same as the cursor of the last result. Since
hasNextPage
is true
, we know there are more results. Let's ask for the
next three results after endCursor
:
- GraphQL
query {
search {
transactions(input: {}, first: 3, after: "MTktMDktMjNUMTM6NTE6MDNa") {
pageInfo {
hasNextPage
startCursor
endCursor
}
edges {
cursor
node {
id
status
}
}
}
}
}
And we get the next three items.
- Response
{
"data": {
"search": {
"transactions": {
"pageInfo": {
"hasNextPage": true,
"startCursor": "MTktMDktMjNUMTM6NDQ6MzZa",
"endCursor": "MTktMDktMjNUMTM6MzE6MjBa"
},
"edges": [
{
"cursor": "MTktMDktMjNUMTM6NDQ6MzZa",
"node": { "id": "dHJhbnNhY3Rpb25fa21wMXBjdG0", "status": "SETTLED" }
},
{
"cursor": "MTktMDktMjNUMTM6NDQ6MTda",
"node": { "id": "dHJhbnNhY3Rpb25fazNtaG42ZnI", "status": "SETTLED" }
},
{
"cursor": "MTktMDktMjNUMTM6MzE6MjBa",
"node": { "id": "dHJhbnNhY3Rpb25fZzZremNidm0", "status": "SETTLED" }
}
]
}
}
},
"extensions": { "requestId": "uVWGQkzkKlHd-Q==" }
}
Empty Results
If you make a query for which there are no results, the edges
array will be empty,
hasNextPage
will be false
, and startCursor
and
endCursor
will be set to null
. For example:
- Response
{
"data": {
"search": {
"transactions": {
"pageInfo": {
"hasNextPage": false,
"startCursor": null,
"endCursor": null
},
"edges": []
}
}
},
"extensions": { "requestId": "w8QZkYHDMho5gw==" }
}