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 .
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.
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.
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.
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.
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.”
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
.
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.
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.