Intro to GraphQL in Apex | Salesforce

Justin Wills
8 min readJul 19, 2023
GraphQL Apex Client Tutorial

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.

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:

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. Thus, 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
  • DELETE

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.

Configure 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 -> Develop 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 is gid://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 the edges 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 named input of type CustomerInput. This variable holds the input data for creating the customer and is provided separately.
  • customerCreate(input: $input): Executes the customerCreate mutation operation with the provided input 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.

This article was originally posted here.

--

--

Justin Wills

Salesforce Consultant Specializing in Connecting Shopify and Quickbooks for Businesses https://www.1sync.co/contact