GraphQL is an API query language that simplifies client-side requests. Apps can do a lot of work with just a single query, such as query multiple resources and entities, request data in a specific format, or get the server to perform several operations.
“At its simplest, GraphQL is about asking for specific fields on objects.” - from GraphQL.org
All queries go to a single endpoint on the server. The server parses queries and returns only the requested data in the requested format.
Visit GraphQL.org for a deeper dive. Check out courses from edx.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 Payroll 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 a simple query to get company information:
1 2 3 4 5 6 7 8 9 | query RequestEmployerInfo { payrollEmployerInfo { businessInfo { name { legalName } } } } |
The server returns values for the legalName
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.
For the QuickBooks Payroll API, you’ll use mutations often for things like transactions and invoices.
Here’s a simple mutation to create an employer deduction:
1 2 3 4 5 6 7 8 9 10 11 | mutation { createEmployerDeduction ( deduction: { name: "My plan deduction" statutoryDeductionPolicy: "Annual max is 10k" } ) { 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.”
For the QuickBooks Payroll API, 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 employees 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 readAllEmployeePayslips { company { employees( pagination: { first: 5, after: null } ) { pageInfo { hasNextPage startCursor endCursor hasPreviousPage } nodes { firstName } } } } |
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": { "employees": { "pageInfo": { "hasNextPage": true, "startCursor": "0", "endCursor": "4", "hasPreviousPage": false }, "nodes": [ <5 employee 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 readAllEmployeePayslips { company { employees( 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.
GraphQL is a powerful and efficient API language. Here are a few ways you can structure and craft your code to build world-class apps.
Only query for the data your app needs In GraphQL, less is more. Create queries that only request the specific fields and data required for your QuickBooks integration to be fully functional. You can change queries later and add more fields as needed.
Log frequently during development Take the time to properly log your app development process. It saves time in the long-run. Logging every execution may impact app performance, so prioritize what matters most.
intuit_tid
field in the server response. It will help our support team quickly find and address any reported issues.Use aliases to query the same field with different arguments Aliases let you rename the results of identical object fields so you can query the same field for different arguments. You can pass multiple queries at once and get responses for both fields without conflict.
Always include operation names to avoid confusion Consciously use operation names to make your code crystal clear, concrete, and unambiguous.
Create fragments to speed up code writing Instead of querying frequently used fields individually, create and reuse fragments whenever possible. This makes code modular and easier to scale.
Pagination lets you quickly navigate large datasets. If you expect a query to return lots of data, use pagination to fetch specific subsets.
Learn about API throttling For information about throttling, see API call limits and throttles.
Single endpoints Let’s say you want to build an invoicing app. It needs to constantly request data for a specific set of invoices. The invoices contain particular items for a specific date range. And, the app needs current business addresses for each customer.
With the REST API, you’d need to make several queries to different endpoints: one for the invoice, one for each customer, and one for each item.
GraphQL only requires a single query, sent to a single endpoint.
Get only the data you need GraphQL queries are highly customizable. You specify the exact fields and values you want the server to return. Apps only get the data you query for–there’s no over-fetching or under-fetching.
Develop with any language GraphQL is language-independent. You can use it with any backend framework or programming language implementation.
Simple data hierarchies GraphQL requests and responses are structured the same way. It naturally follows relationships between attributes.