Magento 2 Create A Custom Module Using GraphQL

Since Magento 2.3.x, GraphQL is a new concept launched where we will see how can we create the simple module using GraphQL and also we will see that how GraphQL interacts with Magento 2.

To create simple GraphQL module using Magento 2, we are creating a test Graphql module using sales order data which will fetch sales order data using our custom module.

We have to create the registration files as registration.php and module.xml to define our module.

Path: app/code/Magemeta/SalesOrderGraphQl/registration.php

<?php
\Magento\Framework\Component\ComponentRegistrar::register(
    \Magento\Framework\Component\ComponentRegistrar::MODULE,
    'Magemeta_SalesOrderGraphQl',
    __DIR__
);

Create module.xml file on following path:

Path: app/code/Magemeta/SalesOrderGraphQl/etc/module.xml

<?xml version="1.0"?>
 
<config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:framework:Module/etc/module.xsd">
    <module name="Magemeta_SalesOrderGraphQl">
        <sequence>
            <module name="Magento_Sales"/>
            <module name="Magento_GraphQl"/>
        </sequence>
    </module>
</config>

We have added the dependency for Sales and GraphQl module in module.xml file to use the core GraphQl functionality with sales data.

Note: Each GraphQl module must contain schema.graphqls file in the etc folder of module.

schema.graphqls is the main file of any GraphQl query implementation which explains what data can be queried in the query. And we can define our custom query structure under the schema.graphqls file.

Every GraphQl service defines a set of types like String, Int, Boolean, Float, Array, Object, enum or Interface which completely describe the set of possible data you can query on specific service.

We need to create schema.graphqls file on following path:

Path: app/code/Magemeta/SalesOrderGraphQl/etc/schema.graphqls

type Query {
    salesOrder (
        id: Int @doc(description: "Id of the sales order")
    ): SalesOrder @resolver(class: "Magemeta\\SalesOrderGraphQl\\Model\\Resolver\\SalesOrder") @doc(description: "The sales order query returns information about a sales order")
}
 
type SalesOrder @doc(description: "Sales order graphql collects the data of specific order information") {
    increment_id: String @doc(description: "Increment Id of sales order")
    customer_name: String @doc(description: "Customer name of sales order")
    grand_total: String @doc(description: "Grand total of sales order")
    is_guest_customer : Boolean @doc(description: "Specifies if this order was placed by guest customer")
    address_array: [String] @doc(description: "Array of order address types. It can have the following values: city, postcode,state")
}

Yo can find the below defined description for each of the field we need to use in GraphQl :

id: Int @doc(description: “Id of the sales order”) it maps to sales order id as Int type
customer_name: String @doc(description: “Customer name of sales order”) it maps to Customer name as String type
is_guest_customer : Boolean @doc(description: “Specifies if the order was placed by guest customer”) it maps to Boolean type
address_array: [String] @doc(description: “Array of order address types. It can have the following values: city, postcode, state”) it maps to Array of data type.

Next, we need to create a Resolver model php file for our custom module and need to define in schema.graphql file. In this Model, resolve() method will simply return data of sales order which fetches the data and formats it according to the GraphQL schema type.

Next we need to create SalesOrder.php file from defined resolver from above schema file:

 SalesOrder @resolver(class: “Magemeta\\SalesOrderGraphQl\\Model\\Resolver\\SalesOrder”) @doc(description: “The sales order query returns data for the sales order”)

Path: app/code/Magemeta/SalesOrderGraphQl/Model/Resolver/SalesOrder.php

<?php
 
declare(strict_types=1);
 
namespace Magemeta\SalesOrderGraphQl\Model\Resolver;
 
use Magento\Framework\Exception\NoSuchEntityException;
use Magento\Framework\GraphQl\Config\Element\Field;
use Magento\Framework\GraphQl\Exception\GraphQlInputException;
use Magento\Framework\GraphQl\Exception\GraphQlNoSuchEntityException;
use Magento\Framework\GraphQl\Query\ResolverInterface;
use Magento\Framework\GraphQl\Schema\Type\ResolveInfo;
 
/**
 * Order sales field resolver for GraphQL request processing
 */
class SalesOrder implements ResolverInterface
{
    public function __construct(
        \Magento\Sales\Api\OrderRepositoryInterface $orderRepository
    ) {
        $this->orderRepository = $orderRepository;
    }
 
    /**
     * @inheritdoc
     */
    public function resolve(
        Field $field,
        $context,
        ResolveInfo $info,
        array $value = null,
        array $args = null
    ) {
        $salesId = $this->getSalesId($args);
        $salesData = $this->getSalesData($salesId);
        return $salesData;
    }
 
    /**
     * @param array $args
     * @return int
     * @throws GraphQlInputException
     */
    private function getSalesId(array $args): int
    {
        if (!isset($args['id'])) {
            throw new GraphQlInputException(__('"sales id should be provided'));
        } 
        return (int)$args['id'];
    }
 
    /**
     * @param int $orderId
     * @return array
     * @throws GraphQlNoSuchEntityException
     */
    private function getSalesData(int $orderId): array
    {
        try {
            $order = $this->orderRepository->get($orderId);
            $shippingAddressArray = [];
            $shippingAddressArray['shipping_name'] = $order->getShippingAddress()->getData('firstname').' '.$order->getShippingAddress()->getData('lastname');
            $shippingAddressArray['city'] = $order->getShippingAddress()->getData('city');
            $shippingAddressArray['postcode'] = $order->getShippingAddress()->getData('postcode');
            $shippingAddressArray['state'] = $order->getShippingAddress()->getData('region');
            $orderData = [
                'increment_id' => $order->getIncrementId(),
                'grand_total' => $order->getGrandTotal(),
                'customer_name' => $order->getCustomerFirstname().' '.$order->getCustomerLastname(),
                'is_guest_customer' => !empty($order->getCustomerIsGuest()) ? 1 : 0,
                'address_array' => $shippingAddressArray
            ];
        } catch (NoSuchEntityException $e) {
            throw new GraphQlNoSuchEntityException(__($e->getMessage()), $e);
        }
        return $orderData;
    }
}

Next we need to run setup:upgrade command to install our custom module.

php bin/magento setup:upgrade
php bin/magento cache:flush

Request Payload: We need to pass required data for sales order where id is our sales order id.

{
  salesOrder(id: 5) {
    increment_id
    grand_total
    customer_name
    is_guest_customer	    
    address_array
  }
}

Output:

{
  "data": {
    "salesOrder": {
      "increment_id": "000000005",
      "grand_total": "100.0000",
      "customer_name": "Magemeta Test",
      "is_guest_customer": false,
      "address_array": [
        "Magemeta Test",
        "test",
        "75020",
        "test"
      ]
    }
  }
}

Leave a Reply