Architect Magento | Tech Blogger | Magento Trainer
Mohamed Abbas | Architect Magento | Tech Blogger | Magento Trainer
Resolvers are essential in GraphQL for Magento, managing request processing. A resolver’s role includes forming a query, retrieving data, performing necessary calculations, transforming data into the GraphQL format, and ultimately returning the result via a callable function.
In Magento’s GraphQL, resolvers process the following arguments:
Magento\Framework\GraphQl\Config\Element\Field
): Describes possible values for a type/interface.Magento\Framework\GraphQl\Query\Resolver\ContextInterface
): A shared, extensible data object for all resolvers using ResolverInterface
.Magento\Framework\GraphQl\Schema\Type\ResolveInfo
): Provides useful information for field resolution.array
): Holds additional query parameters, usually null.array
): Contains query input arguments.Resolvers must implement one of these interfaces:
Batch resolvers are efficient for complex queries, such as retrieving products and related product data all at once, minimizing separate database calls. For example, if querying products and their related products, the resolver could gather requests for each product and retrieve all related items simultaneously.
class RelatedProducts implements BatchResolverInterface
{
public function resolve(ContextInterface $context, Field $field, array $requests): BatchResponse
{
$rootProductIds = array_map(fn($request) => $request->getValue()['model']->getId(), $requests);
$productLinks = $this->service->getRelatedProductLinks($rootProductIds);
$response = new BatchResponse();
foreach ($requests as $request) {
$response->addResponse($request, $productLinks[$request->getValue()['model']->getId()]);
}
return $response;
}
}
This interface is useful for delegating complex data-fetching to a service contract, which returns grouped results for the GraphQL resolver. Here’s an outline of how to structure the resolver and its service contract:
class RelatedProductsResolver implements BatchServiceContractResolverInterface
{
public function getServiceContract(): array
{
return [ProductLinksRetriever::class, 'getRelatedProducts'];
}
public function convertToServiceArgument(ResolveRequestInterface $request)
{
return new RootProductCriteria($request->getValue()['model']->getId());
}
public function convertFromServiceResult($result, ResolveRequestInterface $request)
{
return $result->getLinkedProducts();
}
}
The ResolverInterface
resolves each branch or leaf individually, allowing for on-demand data fetching when invoked. It returns a Value
object that wraps a callable to fetch data only when needed, optimizing data handling.
GraphQL mutations are defined in a schema.graphqls
file under <module_name>/etc
. The example below creates a mutation for an empty cart, specifying resolver and documentation:
type Mutation {
createEmptyCart: String @resolver(class: "\\Magento\\QuoteGraphQl\\Model\\Resolver\\CreateEmptyCart") @doc(description: "Creates an empty shopping cart for a guest or logged-in user")
}
createCustomer
MutationA mutation to create a customer account might look like this:
type Mutation {
createCustomer (input: CustomerInput!): CustomerOutput @resolver(class: "\\Magento\\CustomerGraphQl\\Model\\Resolver\\CreateCustomer") @doc(description: "Create customer account")
}
input CustomerInput {
firstname: String
lastname: String
email: String
password: String
is_subscribed: Boolean
}
mutation {
createCustomer(
input: {
firstname: "Mohamed",
lastname: "Abbas",
email: "test@example.com",
password: "1w2E3R456"
is_subscribed: true
}
) {
customer {
firstname
lastname
email
is_subscribed
}
}
}
{
"data": {
"createCustomer": {
"customer": {
"firstname": "Mohamed",
"lastname": "Abbas",
"email": "test@example.com",
"is_subscribed": true
}
}
}
}
This structured approach with GraphQL resolvers in Magento efficiently manages data and enhances performance by utilizing batching for repeated fields and offloading complex operations to service contracts.
Technical Lead | Magento Architect