Most of the Salesforce Developers, I’d assume, are already aware of GraphQL API. While most developers are familiar with querying data using GraphQL in Lightning Web Components (LWC), the addition of mutations takes this a step further – modifying Salesforce data via the GraphQL API without having to write Apex.
Let us explore what GraphQL mutations are, how to use them in LWC, and provide practical examples of sObject record(s) manipulation.
What Are GraphQL Mutations?
In GraphQL, mutations are operations that provide an entry point for create, update, and delete operations on Salesforce objects. Hence, we now have two operation types in Salesforce’s GraphQL API – namely, Query and (newly GA) Mutation. The mutation operation only supports UI API supported sObjects, as it uses the UI API under the hood for the operations.
Curious enough? Let us see how it looks and works with Lightning Web Components.
Using Mutations in Lightning Web Components
In an LWC, mutations are executed imperatively. Salesforce provides the executeMutation function from the lightning/graphql module for this purpose.
Importing and Setup
import { LightningElement } from 'lwc';
import { gql, executeMutation } from 'lightning/graphql';
Formulating Mutation Query
const query = gql`
mutation <OperationName> {
uiapi {
<objectApiNameAndOperation>(input: {
Id: "...", // Id is only required for update and delete operations
<ObjectApiName> : { // ObjectApiName property is only required for create and update operations
<FieldApiName>: value,
...
}
}) {
record { // Used to specify the fields to fetch; only valid for create and update operations
Id
Field1
Field2
}
Id // For delete operations only
}
}
}
`;
The key syntax to understand is the use of the gql object. gql is a JavaScript template literal function that parses the query. A template literal allows you to create a string with embedded expressions, string interpolations, multiline strings, and HTML templates.
Invoking executeMutation Method
const result = await executeMutation({ query: mutation });
Note: You cannot use @wire with mutations, everything must be handled imperatively.
Now that we are acquainted with the syntax, let us see how we can use GraphQL mutations to create, update, or delete record(s) of a custom object.
Example Response for Creating an Account Record
{
"data": {
"uiapi": {
"accountCreate": {
"Record": {
"Id": "001Ws00005CU3biIAD"
}
}
}
}
}
Usage Examples
Create a New Record
async handleCreate() {
const mutation = gql`
mutation CreateExpenses {
uiapi {
Expense__cCreate(input: {
Expense__c: {
Description__c: "${this.description}"
}
}) {
Record {
Id
Description__c {
value
}
Name {
value
}
}
}
}
}
`;
const result = await executeMutation({ query: mutation });
console.log('Mutation result:', result);
}
Update a Single Record
async handleUpdate() {
const mutation = gql`
mutation UpdateExpense {
uiapi {
Expense__cUpdate(input: {
Id: "${this.expenseId}",
Expense__c: {
Description__c: "${this.description}"
}
}) {
Record {
Id
Description__c {
value
}
Name {
value
}
}
}
}
}
`;
const result = await executeMutation({ query: mutation });
console.log('Mutation result:', result);
}
Apart from the actual mutation syntax, a key piece of mutations is defining how the response from the API will be formed. The Record object defines a follow-up GraphQL query that will produce that result. In doing so, you not only define how the data will change but also the precise feedback that is returned once complete.
Response
{
"data": {
"uiapi": {
"Expense__cUpdate": {
"Record": {
"Id": "a00Ws00000qGlGMIA0",
"Description__c": {
"value": "Updated DESC"
},
"Name": {
"value": "Exp-0000006"
}
}
}
}
}
}
Multiple Operations in a Single Request
Yes, it is indeed possible to perform multiple record operations in a single request (despite not currently being documented in the LWC guide and only in the GraphQL API doc).
In the following example, we will be performing 3 operations in a single request:
- Operation 1: Alias firstAcc; creating an Account 1 without a name.
- Operation 2: Alias secondAcc; Creating a second Account with Name as Account 2.
- Operation 3: Alias updateSecondAcc; updating the Account’s name – which was created in the second operation – by referencing its record Id. The syntax for referencing the record Id is
<FieldName> : @{OperationAlias}.
Please note here the use of allOrNone input. By default, it is set to true. By setting allOrNone to true, you can force a rollback when any of the operations fail in the request. If set to false, only the failed operation is rolled back and not the successfully executed ones.
async handleMultipleOperations() {
const mutation = gql`
mutation MultipleExpenseOperations {
uiapi (input: {allOrNone: false}) {
firstAcc: AccountCreate(input: {
Account: {
Rating: "Hot"
}
}) {
Record {
Id
}
}
secondAcc: AccountCreate(input: {
Account: {
Name: "Account 2"
}
}) {
Record {
Id
}
}
updateSecondAcc: AccountUpdate(input: {
Id: "@{secondAcc}",
Account: {
Name: "Second Account"
}
}) {
Record {
Id,
Name { value }
}
}
}
}
`;
const result = await executeMutation({ query: mutation });
console.log('Mutation result:', result);
}
In the above example, the expected result is:
- Operation 1: Fails with the “Required field (Name) missing” error.
- Operation 2: Successfully creates an Account with the given name.
- Operation 3: Successfully updates the name of the Account created in Operation 2.
Note: Using aliases for operations is a good practice as it allows you to avoid conflicts and provides better readability.
Current Limitations of GraphQL Mutations
While GraphQL mutations are powerful, there are a couple of constraints to be aware of.
- Child relationship creation isn’t supported in a single mutation operation. You can create a record but not its child records (as nested payload) in the same operation. However, you can create a parent and child in a single mutation as different options.
- If you are executing dependent operations in a single request, then all the dependent operations will either all execute successfully or fail collectively.
Summary
The introduction of GraphQL addresses the pain points of app developers building across various platforms, as it adheres to the industry specifications used globally by everyone.
GraphQL mutations empower developers by introducing a flexible, schema-driven way to modify Salesforce data right from Lightning Web Components or via the API.
Comments: