Mohamed Abbas | Architect Magento | Tech Blogger | Magento Trainer

Mohamed Abbas
Mohamed Abbas
Architect Magento | Tech Blogger | Magento Trainer

Resolvers

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:

  • $field (Magento\Framework\GraphQl\Config\Element\Field): Describes possible values for a type/interface.
  • $context (Magento\Framework\GraphQl\Query\Resolver\ContextInterface): A shared, extensible data object for all resolvers using ResolverInterface.
  • $info (Magento\Framework\GraphQl\Schema\Type\ResolveInfo): Provides useful information for field resolution.
  • $value (array): Holds additional query parameters, usually null.
  • $args (array): Contains query input arguments.

Resolvers must implement one of these interfaces:

  1. BatchResolverInterface: Resolves multiple requests in a single operation by gathering requests for a field until previous ones must be resolved.
  2. BatchServiceContractResolverInterface: Batches requests similarly but delegates actual resolution to a batch service contract.
  3. ResolverInterface: Resolves requests individually.

BatchResolverInterface Example

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.

Pseudo-code for a Batch Resolver:

				
					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;
    }
}

				
			

BatchServiceContractResolverInterface Example

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();
    }
}

				
			

ResolverInterface

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.

Example Mutation

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")
}

				
			

Sample createCustomer Mutation

A 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
}

				
			

Sample Request and Response

				
					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.

Picture of Mohamed Abbas

Mohamed Abbas

Technical Lead | Magento Architect