GraphQL basics

The QuickBooks Online GraphQL API uses the GraphQL API framework. Here’s a brief overview.

Learn about best practices and the advantages of GraphQL and what makes it a great API framework. For a deeper dive, visit GraphQL.org .

Create queries to request data

In GraphQL, queries can fetch data for single or multiple fields, apply filters, and get conditional data. If you’re familiar with the REST API, this is very similar to the GET operation. However, queries in GraphQL are always POST operations.

GraphQL queries are very efficient. When apps send requests with queries, the server only returns the requested data. The response will be the same shape and format as the query.

Server responses are clean, specific, and easy to work with. This also boosts app performance. Servers don’t slow down to fetch unusable or extraneous data.

How to create queries

For the QuickBooks GraphQL API, use queries to get data for accounts, transactions, and other resources. Specify the exact fields you want the server to return in the query body.

Here’s an example of a query to get company information:

1
2
3
4
5
6
7
          query getCompanyInformation {
            {
              company {
                name
              }
            }
          }

The server returns values for the name field.

Learn more about queries from GraphQL.org.

Use mutations to modify data

Mutations are what apps use to perform operations to change, update, or delete data on the server.

In GraphQL, you can use mutations to modify multiple fields with a single request. If you’re familiar with the REST API, mutations are similar to the POST, PUT, and DELETE operations.

While it’s possible to create and update data with queries in GraphQL, it’s best practice to use mutations to change or update data. And unlike queries, mutations run in series instead of in parallel.

How to use mutations

You’ll use mutations to create or update entities and transactions. Here’s an example of a mutation to create a dummy transaction.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
          mutation {
            createTransaction (
              transaction: {
                name: "Sample transaction"
              }
            ) {
              id
              name
            }
          }

Mutations typically take input data and define fields based on the response the server returns.

In this example, the mutation took the deduction argument and let the server define the id and name fields based on the response.

Create fragments for sets of fields

Fragments are reusable sets of fields you can use across queries.

In GraphQL, you can define and group sets of fields into fragments. Instead of repeating individual fields, simply call the fragment to utilize all the fields and related data at once.

This lets you organize code into modular, bite-sized “chunks.”

How to create and use fragments

Fragments are useful for queries that constantly reuse the same sets of fields.

Here’s an example of defining a fragment and using it in a query:

1
2
3
4
5
6
7
          query
            queryName {
              fieldName1
              fieldName2 {
                ...fragmentName
              }
            }

We put fragmentName in fieldName2.

Now define the fragment and corresponding set of fields:

1
2
3
4
5
6
          fragment
            fragmentName on FieldName {
              field1
              field2
              field3
            }

Now, instead of entering each individual field, you can just use fragmentName.

Use pagination to fetch subsets of data

Pagination lets you quickly search and request subsets of data within larger datasets.

In GraphQL, you can use the pageInfo object and cursor-based pagination (endCursor and startCursor) to set criteria or collect data after a certain point in the response. This typically yields smaller payloads and faster server responses.

For more about GraphQL pagination, see GraphQL Cursor Connections Specification.

Implement pagination

When querying a group of records, we recommend implementing pagination to avoid timeout errors. We suggest requesting 10 records at a time. The general format for pagination is:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
          query queryName {
            fieldName1
            fieldName2(pagination: {first: numOfRecords, after: cursorValue}) {
             pageInfo {
                hasNextPage
                startCursor
                endCursor
                hasPreviousPage
              }
              field1
              field2
            }
          }

In this example, numOfRecords is the number of records you want returned by the query. The field cursorValue is the pointer to the first element that the count should begin from. numRecords is an Integer field and cursorValue is a String field.

Let’s take an example where there are 20 transactions in the system and you want to read 5 at a time. The first time you send a request, set your cursorValue to null. Your query will look like this:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
          query readAllRecords {
                  company {
                          transactions(
                                  pagination: { first: 5, after: null }
                          ) {
                                  pageInfo {
                                          hasNextPage
                                          startCursor
                                          endCursor
                                          hasPreviousPage
                                  }
                                  nodes {
                                          name
                                  }
                          }
                  }
          }

The response will return records 1 - 5:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
          {
            "data": {
              "company": {
                     "transactions": {
                            "pageInfo": {
                                    "hasNextPage": true,
                                    "startCursor": "0",
                                    "endCursor": "4",
                                    "hasPreviousPage": false
                            },
                            "nodes": [
                               <5 transactions nodes with data>
                            ]
                      }
                    }
             }
          }

From this response, if hasNextPage = true, get the value of endCursor and in your next query to read records 6 - 10, increment and pass this value as the cursorValue. So your next query will look like this

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
          query readAllRecords {
            company {
                  transactions(
                    pagination: { first: 5, after: "5" }
                  ) {
                          pageInfo {
                            hasNextPage
                            startCursor
                            endCursor
                            hasPreviousPage
                          }
                          nodes {
                            firstName
                          }
                    }
             }
          }

This will return records 6 - 10. You continue to do this as long as there are more records to be read. The field hasNextPage in the response is an indicator of whether there are more records left to be read or not. Once the last set of records are reached, the value of hasNextPage will be false.