Create a Custom module using Graphql in Magento 2.

GraphQL is a new concept from Magento 2.3 and Many Magento Enthusiastic have eagerly waiting for the simple module using GraphQL and how GraphQL interacts with Magento 2 and why GraphQL is used for Magento 2 and so many other stuff around GraphQl.

I want to give a demo of a simple module of GraphQL in Magento 2. How GraphQl is actually used in Magento 2 using programmatic way and so on.

I hope you are aware of What is GraphQl and how GraphQL are used for the programming language like Magento 2 If You are new to GraphQL check link for GraphQl in Magento 2.

I hope you are aware of creating a simple module in Magento 2, Check link. How to create a simple module in Magento 2?

For Create Simple GraphQl module using Magento 2, We are creating a Demo Graphql module using Sales Data, Our Main Aim is to fetch sales related data using Custom module.

You need to create first registration.php and module.xml file for defining our module.

Path: app/code/Rbj/DemoGraphQl/registration.php

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

Create module.xml file, Path: app/code/Rbj/DemoGraphQl/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="Rbj_DemoGraphQl">
        <sequence>
            <module name="Magento_Sales"/>
            <module name="Magento_GraphQl"/>
        </sequence>
    </module>
</config>

Our Module is depends on GraphQL and Sales Module so we have given dependency on module.xml file.

Every GraphQl Module must contain schema.graphqls file under the etc folder of a module.

schema.graphqls is at the center of any GraphQL Query implementation and describes the what data can be queried. So You can define your query data basic skeleton 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.

You can learn more detail for a schema by https://graphql.org/learn/schema/

Create schema.graphqls file, Path: app/code/Rbj/DemoGraphQl/etc/schema.graphqls

type Query {
    salesOrder (
        id: Int @doc(description: "Id of the Sales Order")
    ): SalesOrder @resolver(class: "Rbj\\DemoGraphQl\\Model\\Resolver\\SalesOrder") @doc(description: "The Sales Order query returns information about a Sales order")
}

type SalesOrder @doc(description: "Sales Order graphql gather Data of specific order information") {
    increment_id: String @doc(description: "Increment Id of Sales Order")
    customer_name: String @doc(description: "Customername 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 cusotmer")
    address_array: [String] @doc(description: "Array of order address types. It can have the following values: city, postcode,state")
}

In this blog, we learn about only Query type of GraphQl.
We have defined the description of each field we need to use in GraphQl,

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

Now Create a Resolver Model for our custom module. Resolver Model class which is defined in schema.graphql file at above. In this Model, resolve() method will simply return data of sales Order.

Resolver method fetches the data and formats it according to the GraphQL schema type.

We need to create SalesOrder.php file from defined resolver from above schema file SalesOrder @resolver(class: “Rbj\\DemoGraphQl\\Model\\Resolver\\SalesOrder”) @doc(description: “The Sales Order query returns information about a Sales order”)

Path: app/code/Rbj/DemoGraphQl/Model/Resolver/SalesOrder.php

<?php

declare(strict_types=1);

namespace Rbj\DemoGraphQl\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, used 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 specified'));
        }

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

In the above file, resolve() method contains the method getSalesData() which is responsible for getting data of GraphQl. You need to define your custom logic in resolve method.

Now Run Upgrade command to install our module.

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

You can check your GraphQL query response by installing chrome extension ChromeiQL or Altair GraphQL addon.

Check Using type query in ChromeiQl by,
http://127.0.0.1/magento2-2.3-develop/graphql where http://127.0.0.1/magento2-2.3-develop is your store URL.

Custom GraphQL module
Custom GraphQL module

In Request Body, You need to pass required data for Sales Order, Where id is your Order id.

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

The result will be,

{
  "data": {
    "salesOrder": {
      "increment_id": "000000001",
      "grand_total": "525.0000",
      "customer_name": "Rakesh Jesadiya",
      "is_guest_customer": false,
      "address_array": [
        "Rakesh Jesadiya",
        "Ahmedabad",
        "380001",
        "Gujarat"
      ]
    }
  }
}