· tutorials · 10 min read
Using GraphQL in Apex | Full Guide
Learn how to leverage GraphQL in Salesforce with the GraphQL Apex Client. Discover the advantages of GraphQL over REST, implement streamlined data retrieval, mutations, and boost performance.
GraphQL is a query language that allows developers to retrieve and mutate data within a service. This is a more efficient alternative to REST, a set of guidelines for developing an API to interact with data. GraphQL has become more prominent in the past few years. Companies like Netflix and Shopify have implemented GraphQL in favor of REST to improve performance. With the rise of GraphQL, it is critical to know how to use this new interface, and how to use this in Apex development.
Why Use GraphQL
GraphQL is the best way to query exactly what you need. A developer queries the exact data set required. No more, no less. GraphQL addresses several limitations of traditional RESTful APIs by providing developers with a powerful alternative for fetching and manipulating data.
Notable Companies using GraphQL
Many companies going public about there migration to GraphQL with their backend services and public APIs. A short list of implementations include:
- Shopify B2B APIs are only available with GraphQL.
- Shopify are using GraphQL as the preferred service.
- Salesforce Released GraphQL endpoints in Winter ‘23.
- Netflix implemented GraphQL for their internal services.
GraphQL Queries - Streamlined Data Retrieval
The biggest advantage of GraphQL is the ease of retrieving the exact data that you need. Making an API request through REST will return a fixed set of data. This data set returned results in one of two scenarios. More data than required is returned, categorized as over-fetching. Or not enough data is returned, requiring multiple API calls. This is often referred to as under-fetching.
GraphQL fixes this by allowing you to specify the exact data required in one query. These queries can be built with the exact data required, so the problems of over-fetching and under-fetching are no longer lingering. Additionally, the ability to specify the exact fields and related objects in one query reduces the need for multiple API calls.
Example: Shopify API - Customer
Let’s say we had a customer in Shopify, and a custom metafield called Salesforce Id
that we were trying to retrieve within Shopify. Through the API, we want the user’s first name, last name, and email. With REST, the following api queries would be required:
GET
-/customer/{customer-id}.json
GET
-/customer/{customer-id}/metafield/{metafield-id}.json
In addition to two queries, there is a litany of data that is returned through the API which is not needed for our use case. With GraphQL, we can use the following query on one endpoint to retrieve exactly what we need:
query {
customer(id: "gid://shopify/Customer/{customer-id}") {
email
firstName
lastName
metafield(namespace: "salesforce", key: "sf_id") {
value
}
}
}
GraphQL - Editing Data with Mutations
Manipulating data through GraphQL is done through mutations. The corollary for mutations would be the various endpoints in a REST API, as well as various methods. E.g. to modify data for a customer in Shopify, you can use the following HTTP methods for the /customer
endpoint:
GET
POST
PUT
DEL
With GraphQL, these endpoints and methods are consolidated under one endpoint. Mutations are used for creating, modifying, and deleting data within the system.
Using GraphQL in Apex
Implementing GraphQL in Apex is easy using the GraphQL Apex Client by Ilya Matsuev. This is a client that allows us to easily construct GraphQL queries and mutations.
Installing Salesforce Apex GraphQL Client
Easiest way to install is the GraphQL Apex Client is by using SFDX plugin install
sfdx force:package:install -p 04t5Y000001zNZLQA2 -w 10 -b 10 -u <username>
This installs all the necessary components as an unmanaged package in SF.
You can then pull components back into VS Code by adding the components in your package.xml
manifest and retrieving the source from org.
Congifure Shopify APIs
This demo will use the Shopify APIs. You can create a sandbox store by signing up for a partner account, then creating a development store.
How to Install GraphiQL Explorer in Shopify
We can use the GraphQL explorer to preview and make GraphQL calls to test our queries. You can install the GraphiQL explorer here.
You can choose what permissions are needed. For the demo, we need:
- Write Customer
- Read Order
If you need to change the permissions, you can go back to the website above and reinstall with new permissions.
Once the GraphiQL is installed, we can verify the installation by running the following query
query {
shop {
name
}
}
The query will return the following JSON information:
{
"data": {
"shop": {
"name": "your-store-name"
}
},
"extensions": {
"cost": {
"requestedQueryCost": 1,
"actualQueryCost": 1,
"throttleStatus": {
"maximumAvailable": 1000,
"currentlyAvailable": 999,
"restoreRate": 50
}
}
}
}
Congrats! You made your GraphQL query!
Sidenote about Shopify GraphQL Syntax
If you use the prettify function on the above GraphQL query, you may notice that the query
label is removed, resulting in the following query:
{
shop {
name
}
}
These are the same queries, but something to be aware of! I will be using this style of query moving forward.
Querying Customer From Shopify
Let’s say we want to query a specific customer from Shopify using the customer’s Id. We can use this by passing in the Id as an argument in the Customer query. The resulting query would look like the following:
{
customer(id: "gid://shopify/Customer/7051972051262") {
firstName
lastName
}
}
We can get customer by the Id and see the following data:
{
"data": {
"customer": {
"firstName": "Justin",
"lastName": "Wills"
}
},
"extensions": {
"cost": {
"requestedQueryCost": 1,
"actualQueryCost": 1,
"throttleStatus": {
"maximumAvailable": 1000,
"currentlyAvailable": 999,
"restoreRate": 50
}
}
}
}
Turn into Apex:
We can turn this into Apex code. First we need to make a custom app. Go to Settings
-> Apps and sales channels
-> Devlop apps
and Create an App. Give the app the following properties:
- App name:
Salesforce Integration
- App developer: your email
From here we can go to Configure Admin API scopes
and grant the following scopes:
write_customers
read_customers
read_orders
Save the permissions and go to API Credentials
. Press Install app
and copy down the Admin API access token
. We will need this later for authenticating into Salesforce.
From here, let’s pivot to VS Code and start developing. Create the following class to store this code: ShopifyGraphQL
We can use the following method to create the GraphQL query in Apex:
public static void getCustomer(){
GraphQLField customer = new GraphQLField('customer');
customer.withField('firstName');
customer.withField('lastName');
customer.withArgument('id', 'gid://shopify/Customer/7051972051262');
GraphQLQuery query = new GraphQLQuery(
new List<GraphQLField> { customer }
);
System.debug(query.build(true));
}
And to send the query, we can use the following code:
private static void sendQuery(GraphQLQuery query){
GraphQLRequest request = query.asRequest();
// Add custom Shopify Header
request.withHeader('X-Shopify-Access-Token', 'Shopify-access-token');
request.withHeader('Content-Type', 'application/json');
// Provide a GraphQL endpoint to the client
String shop = 'your-store-url';
String apiVersion = '2023-07';
GraphQLHttpClient client = new GraphQLHttpClient('https://' + shop +'.myshopify.com/admin/api/'+ apiVersion +'/graphql.json');
GraphQLResponse response = client.send(request);
// Check if there are any errors and data
System.debug(response.hasErrors());
System.debug(response.getErrors());
System.debug(response.hasData());
System.debug(response.getData());
}
Where the access token is the string value from the previous step, and the store url is the url from your store.
We can add this to the getCustomer()
method to send out the request to Shopify’s server:
public static void getCustomer(){
GraphQLField customer = new GraphQLField('customer');
customer.withField('firstName');
customer.withArgument('id', 'gid://shopify/Customer/7051972051262');
GraphQLQuery query = new GraphQLQuery(
new List<GraphQLField> { customer }
);
System.debug(query.build(true));
sendQuery(query);
}
Now when you run the following code in execute anonymous, you can see the same JSON response from your developer logs
ShopifyGraphQL.getCustomer();
Query Customers with Related Orders
Let’s say this customer has multiple orders, and you are looking to query a customer with related orders. With GraphQL, this can be done with 1 query. Take the following query:
{
customer(id: "gid://shopify/Customer/7051972051262") {
firstName
orders(first: 5) {
edges {
node {
name
}
}
}
}
}
We query the same customer resource, by passing in the argument id
. Additionally, we add orders as a field, and pass in the first
argument. Shopify requires a limit on the amount of related objects being queried. Shopify’s GraphQL format to get related objects is to then pass edges
and node
as nested fields, then query fields from the order.
This GraphQL query retrieves information about a specific customer from the Shopify API and their most recent orders. Here’s a breakdown of each component:
customer
: Specifies that we want to retrieve information about a customer.id
: Specifies the ID of the customer we want to retrieve information for. In this case, the ID isgid://shopify/Customer/7051972051262
.firstName
: Requests the first name of the customer.orders
: Requests information about the customer’s orders.first
: Specifies the maximum number of orders to retrieve. In this case, it’s set to 5.edges
: Represents a connection to a list of objects. In this case, it connects to the list of orders.node
: Specifies the actual order object within theedges
connection.name
: Requests the name of each order.
Translate to Apex
We can take this query and turn it into Apex code:
public static void getCustomerWithOrders(){
GraphQLField customer = new GraphQLField('customer');
customer.withField('firstName');
customer.withArgument('id', 'gid://shopify/Customer/7051972051262');
GraphQLField orders = new GraphQLField('orders');
orders.withArgument('first', 5);
GraphQLField order = new GraphQLField('node');
order.withField('name');
orders.withField(new GraphQLField('edges').withField(order));
customer.withField(orders);
GraphQLQuery query = new GraphQLQuery(
new List<GraphQLField> { customer }
);
System.debug(query.build(true));
sendQuery(query);
}
Create a Customer using Mutations
We can create a customer using the customerCreate
mutation. See the following mutation below:
mutation customerCreate($input: CustomerInput!) {
customerCreate(input: $input) {
customer {
firstName
lastName
}
userErrors {
field
message
}
}
}
mutation
: Indicates that this is a mutation operation that will modify data.customerCreate
: Specifies the mutation operation to create a customer.$input
: Defines a variable namedinput
of typeCustomerInput
. This variable holds the input data for creating the customer and is provided separately.customerCreate(input: $input)
: Executes thecustomerCreate
mutation operation with the providedinput
variable.customer
: Represents the newly created customer.firstName
: Requests the first name of the customer.lastName
: Requests the last name of the customer.userErrors
: Represents any errors that occur during the mutation.field
: Retrieves the field associated with an error.message
: Provides the error message associated with the field.
We also need to pass in the customer data as a JSON formatted data. The JSON data may look something like this:
{
"input": {
"firstName": "Justin",
"lastName": "Wills"
}
}
Translate to Apex
We can translate this query into Apex with the following code:
public static void createCustomer(){
GraphQLField customerCreateNode = new GraphQLField('customerCreate')
.withArgument('input', '$input');
GraphQLField customerNode = new GraphQLField('customer').
withFields( new List<String>{'firstName', 'lastName'});
GraphQLField userErrorsNode = new GraphQLField('userErrors')
.withFields( new List<String>{'field', 'message'} );
customerCreateNode.withField(customerNode);
customerCreateNode.withField(userErrorsNode);
GraphQLMutation mutation = new GraphQLMutation('customerCreate', customerCreateNode)
// Define variable for the mutation
.defineVariable('input', 'CustomerInput!');
Customer customer = new Customer();
customer.firstName = 'Justin';
customer.lastName = 'Wills';
GraphQLRequest request = mutation.asRequest()
.withVariable('input', customer);
sendMutation(request);
}
private static void sendMutation(GraphQLRequest request){
// Add custom header if needed
request.withHeader('X-Shopify-Access-Token', 'your-access-token');
request.withHeader('Content-Type', 'application/json');
// Provide a GraphQL endpoint to the client
String shop = 'your-store-name';
String apiVersion = '2023-07';
GraphQLHttpClient client = new GraphQLHttpClient('https://' + shop +'.myshopify.com/admin/api/'+ apiVersion +'/graphql.json');
GraphQLResponse response = client.send(request);
// Check if there are any errors and data
System.debug(response.hasErrors());
System.debug(response.getErrors());
System.debug(response.hasData());
System.debug(response.getData());
}
public class Customer {
String firstName;
String lastName;
}
Notice the wrapper class at the bottom to store the customer data as an object that get’s translated to the JSON input.
We also make a different method, sendMutation
that takes a GraphQLRequest
over a GraphQLQuery
.
Conclusion
GraphQL is a new way of accessing third-party data. With large companies like Netflix and Shopify adopting this approach to access their data, GraphQL’s popularity will only rise. Using a library to generate GraphQL requests will speed up development, and improve code readability.
Need Our Help To Get Your Data Into Salesforce?
Join dozens of other companies by learning how you can get all your company's data in one place.