FPI Mutation Functions
Custom GraphQL functions enable extensions to intercept and modify GraphQL mutations/queries triggered by the storefront. It empowers developers to customize the behavior of frontend GraphQL operations dynamically—without altering the core theme code—making storefronts more extensible and interactive.
Key Components
The Custom GraphQL flow consists of three primary components:
- Storefront: Initiates GraphQL queries/mutations based on user interactions.
- Extensions: Register callback functions to intercept and modify queries/mutations through UI functions (e.g., Product Customisation extension).
- FDK Store: Merge extension inputs with the original GraphQL operations and forward them to the GraphQL server.
FPI Instance
To access the FPI instance in your application:
- In React components: Use the
useFPI
hook. - In Vanilla JavaScript: The FPI object is available globally on the browser's window object.
This approach ensures you can interact with the FPI client effectively, whether you're working within React or plain JavaScript environment.
Mutation Property
The Mutation (mutation
) property has been introduced in the fpi
instance. It provides two key methods:
public mutations = {
apply: Function,
remove: Function,
}
Apply Mutation
Applying a mutation enables extensions to intercept a GraphQL operation by its mutation name. The Apply method is the primary mechanism for registering extension-level interception logic on a GraphQL query or mutation originating from the theme. This allows developers to inject custom logic, transform request inputs, augment queries, or mock server responses — all without modifying theme code or backend services.
Parameters
operationName
(string): Name of the GraphQL query/mutation you want to intercept (e.g.,"addItemsToCart"
). Must match exactly the operation name used by the theme (e.g.,"addItemsToCart"
). If the name doesn’t match, the interceptor will not be triggered.callback
(function): Receives the original request payload and returns a modified object. An asynchronous or synchronous function that is invoked when the specified operation is executed. Should return an object that modifies the GraphQL request/response.
Return Object Structure
The callback should return an object that may include up to three properties:
//used when adding/updating request keys before calling core API
return {
requestParam: { ...updatedRequest }, // Optional Modified input for GraphQL server
query: someGraphQLQuery, // Optional updated query
};
requestParam
: Updated payload forwarded to the GraphQL server.query
: Custom query with the sameoperationName
. If the name doesn't match the theme's original, an error will be thrown.- One query may contain multiple GraphQL fields.
- Any changes to the same field will override the theme's.
- Use this to append or modify fields within the operation.
//used to bypass core API and returns the response provided here
return {
response: { ...updatedResponse }, // Optional mocked response
};
response
: If returned, the theme receives this as the response.- Useful for validation logic or simulating failures/successes.
- Should mimic GraphQL response structure, including
data
orerrors
.
Avoid combining response
with requestParam
and query
in the return object. However, this won't trigger an error and will short-circuit the flow—preventing any modified query or payload from being forwarded to the server.
response
: to mock or short-circuit the GraphQL operation.requestParam
+query
: to modify and forward the operation to the server.
Multiple callbacks registered with the same operation will execute in the order they are applied.
Maintaining GraphQL Response Structure
When using a custom GraphQL function to intercept a GraphQL mutation or query and return a response, the structure of the returned object must match the GraphQL response schema.
GraphQL clients (like storefront) rely on a standardized structure to interpret:
data
: Holds actual data returned by the server (or extension).errors
: Array of objects representing any GraphQL errors that occurred.
Failing to follow this structure may result in improper rendering or the failure of critical theme logic.
Examples
1. Customize Products
The following example shows three key concepts enabled by mutation in the FDK:
Extensions can intercept theme-triggered GraphQL mutations and inject custom data into the request. This is especially useful for personalization scenarios—such as attaching user-selected attributes (e.g., jersey numbers, engraving text) to cart items—without needing the theme to handle such logic explicitly. It allows the extension to enrich the GraphQL input dynamically before it’s sent to the server.
In addition to modifying the input payload (requestParam), extensions can also override or augment the GraphQL query itself. This enables structural changes to the operation—for instance, adding new fields, nesting custom inputs, or transforming the query to match the backend’s evolving schema. The modified query must retain the same operation name to ensure compatibility with the theme’s original GraphQL intent.
Extensions can entirely short-circuit a GraphQL operation by returning a response object. This simulates either a successful result or an error, which is sent back to the theme immediately. This is particularly useful for pre-check validations, fallback responses, or test cases. However, when a response is returned, any modifications to the request parameters or query are ignored—ensuring only one path of control is active.
Together, these features offer powerful, middleware-like control over storefront behavior, allowing extensions to enhance, control, or simulate the behavior of theme GraphQL operations with full flexibility.
const jerseyNumber = 8;
const itemId = 'xx'
fpi.mutations.apply("updateCart", async (req) => {
const items = req.updateCartRequestInput.items.map(x => {
if(x.item_id == item_id) {
item.custom_json.jersey_number = jerseyNumber;
}
})
return {
...
requestParam: {
...req,
updateCartRequestInput: {
... request.updateCartRequestInput,
items
},
otherKey: ""
},
query:someGraphQLQuery,
... // for errors
response: {
"errors": [
{
"code": "FDK_SERVER_RESPONSE_ERROR",
"status_code": 400,
"message": "User BOT verification required",
"status": "Bad Request",
"path": [
"verifyMobileOTP"
],
"details": {
"message": "User BOT verification required"
}
}
],
"data": {
"verifyMobileOTP": null
}
},
}
}
)
2. Validate a Payload
This code snippet demonstrates how an extension can intercept the verifyMobile
GraphQL mutation using the fpi.mutations.apply
method. It checks whether the OTP was sent via WhatsApp. If true, it triggers a custom function to perform OTP validation on the extension side—typically through an API call. Instead of letting the request proceed to the backend, it returns a mocked GraphQL-compliant response, that simulates a successful verification. This short-circuits the original flow and allows the theme to behave as if the OTP has been verified, enabling support for alternative verification channels, such as WhatsApp.
const isOtpSentOnWhatsApp = true;
const verifyValidOtp = (otp) => {
// Make extension-side API call
};
fpi.mutations.apply("verifyMobile", **async (request) => {
if (isOtpSentOnWhatsApp) {
verifyValidOtp(request.codeRequestBodySchemaInput.code);
return {
response: {
data: {
verifyMobile: {
// ...custom mocked response
}
}
}
};
}
})
3. Error handling using response
This code snippet demonstrates how to use fpi.mutations.apply
for error handling by returning a custom response object. If the isRobot
flag is true, the extension intercepts the verifyMobile mutation and returns a mocked error response. The structure includes a GraphQL-compliant errors array and a null data payload, simulating a backend rejection with a bad Request status. This allows the theme to display an appropriate error message (e.g., “User BOT verification required”) without hitting the actual server.
const isRobot = true; // Set based on reCAPTCHA token validation
fpi.mutations.apply("verifyMobile", async () => {
if (isRobot) {
return {
response: {
errors: [
{
code: "FDK_SERVER_RESPONSE_ERROR",
status_code: 400,
message: "User BOT verification required",
status: "Bad Request",
path: ["verifyMobileOTP"],
details: {
message: "User BOT verification required",
},
},
],
data: {
verifyMobileOTP: null,
},
},
};
}
});
4. Returning a modified response
This snippet shows how to return a custom modified response directly from an extension without modifying the request or query. When the someMutation
operation is triggered, the extension intercepts it and returns a predefined updated response. This short-circuits the original GraphQL flow, preventing the request from reaching the server. It is useful for testing, mocking server behavior, or overriding responses based on extension-specific logic.
fpi.mutations.apply("someMutation", async (request) => {
return {
response: {
...updatedResponse,
},
};
});
5. Returning updated request and query
This code snippet demonstrates how to modify and forward a GraphQL mutation from the theme. When someMutation
is triggered, the extension intercepts it using fpi.mutations.apply
, updates the input parameters, and optionally replaces the GraphQL query with a customized one. This allows the extension to inject additional data or modify the structure of the request before it’s sent to the server, enabling control over GraphQL operations.
fpi.mutations.apply("someMutation", async (request) => {
return {
requestParam: {
...updatedRequest,
},
query: someGraphQLQuery,
};
});
Remove Mutation
Use Remove mutation to deregister a mutation or query callback:
- If callback is provided, only that specific callback will be removed.
- If no callback is provided, all callbacks for the given operation name will be removed.
fpi.mutations.remove("someMutation");
fpi.mutations.remove("someMutation", asyncFunction);