What You Need to Know about GraphQL in Magento
Finding various approaches to working with APIs is easy, yet GraphQL emerges to be the most victorious for the simple fact because its many strengths can benefit you in the best way. But, what exactly is GraphQL and why so much buzz around it? Let’s figure out more here.
GraphQL is a data query language developed by Facebook. Magento supports GraphQL along with REST API architecture. There are some awesome GraphQL APIs already provided by Magento as a part of the installation.
Magento provides default GraphQL APIs for some of its modules. To access these APIs there are different API testing tools like GraphiQL, Postman, Firecamp, and so on. In this article, we make use of the GraphiQL chrome extension to test our GrpahQL APIs.
Grapql supports two types of operations :
- Queries
- Mutation
Queries are used to fetch only data from the database, whereas mutations are used to make changes in the database such as adding new records, updating existing records, deleting records. You can check out the existing GraphQL queries and mutations at your_domain_name/graphql endpoint.
How to create graphql API for your custom Magento module
As we know, in Magento development services, to build any custom Magento module we need the Vendor name and module name. In the article, we have used Sjinnovation as vendor name and GraphqlDemo as the module name. Let's get started with the basic steps involved in creating a Magento module.
Create module.xml
app\code\Sjinnovation\GraphqlDemo\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="Sjinnovation_GraphqlDemo" setup_version="1.1.0">
<sequence>
<module name="Magento_GraphQl"/>
<module name="Sjinnovation_Videos"/>
</sequence>
</module>
</config>
To use Graphql in the custom module we need to specify a Magento graphql module in the dependency list ( i.e Magento_GraphQl) of our module.xml file. Additionally, you can specify the other necessary modules as per your requirement. We have used a module Sjinnovation_Videos which does all the required CRUD operations on the custom table in the database.
Register the module
app\code\Sjinnovation\GraphqlDemo\registration.php
<?php \Magento\Framework\Component\ComponentRegistrar::register(
\Magento\Framework\Component\ComponentRegistrar::MODULE,
'Sjinnovation_GraphqlDemo',
__DIR__
);
GraphQL Query
Setup Graphql Schema
Create a new file with the name schema.graphqls in etc directory
app\code\Sjinnovation\GraphqlDemo\etc\schema.graphqls
type Query {
getVideoData : [VideoData] @resolver (class:"\\Sjinnovation\\GraphqlDemo\\Model\\Resolver\\VideoDataResolver") @doc(description:"List of videos")
}
type VideoData {
video_id: Int @doc(description: "Video Id")
title: String @doc(description: "Video Title")
sub_title: String @doc(description: "Video Sub-title")
url: String @doc(description: "Video URL")
banner_url: String @doc(description: "Video Banner URL")
}
Let’s look at the above code. To define any query operation make use of query type. In the above code :
- getVideoData is the query name.
- VideoData is a custom graphql return type
- @resolver specifies the resolver class which will be invoked when the getVideoData query gets fired.
- @doc allows to insert documentation for query, fields
- VideoData returns the object having video id, title, sub-title, URL, and banner URL.
Setup Resolver for GraphQL query
Let’s create a resolver class for the above query. Create VideoDataResolver class at \Sjinnovation\GraphqlDemo\Model\Resolver directory.
<?php
declare(strict_types=1);
namespace Sjinnovation\GraphqlDemo\Model\Resolver;
use Magento\Framework\GraphQl\Config\Element\Field;
use Magento\Framework\GraphQl\Exception\GraphQlInputException;
use Magento\Framework\GraphQl\Query\ResolverInterface;
use Magento\Framework\GraphQl\Schema\Type\ResolveInfo;
use Magento\Framework\Exception\NoSuchEntityException;
use Magento\Framework\GraphQl\Exception\GraphQlNoSuchEntityException;
class VideoDataResolver implements ResolverInterface
{
/**
* @param Field $field
* @param \Magento\Framework\GraphQl\Query\Resolver\ContextInterface $context
* @param ResolveInfo $info
* @param array|null $value
* @param array|null $args
* @return array|\Magento\Framework\GraphQl\Query\Resolver\Value|mixed
* @throws GraphQlInputException
*/
private $dataProvider;
public function __construct(
\Sjinnovation\GraphqlDemo\Model\Resolver\DataProvider\Videos $dataProvider
) {
$this->dataProvider = $dataProvider;
}
public function resolve(
Field $field,
$context,
ResolveInfo $info,
array $value = null,
array $args = null)
{
return $this->dataProvider->getVideos();
}
}
Let’s have a look at the resolver code. The first step, import all the required GrapQL dependencies. The next step is to implement ResolverInterface. Following this, define required dependencies in the class constructor. Here we have created a data provider which will fetch the required results. And at last override resolve function which makes a call to function of the data provider and returns the result.
Lets create data provider. Create Videos class at \Sjinnovation\GraphqlDemo\Model\Resolver\DataProvider
<?php
namespace Sjinnovation\GraphqlDemo\Model\Resolver\DataProvider;
use Magento\Framework\Exception\NoSuchEntityException;
use Magento\Framework\GraphQl\Exception\GraphQlNoSuchEntityException;
use Magento\Framework\Exception\LocalizedException;
class Videos
{
protected $_videoFactory;
protected $_objectManager;
public function __construct(
\Sjinnovation\Videos\Model\ResourceModel\Videos\CollectionFactory $videoFactory,
\Magento\Framework\ObjectManagerInterface $objectManager
)
{
$this->_videoFactory = $videoFactory;
$this->_objectManager = $objectManager;
}
public function getVideos()
{
$videoData = [];
try {
$collection = $this->_videoFactory->create();
$videoData = $collection->getData();
} catch (NoSuchEntityException $e) {
throw new GraphQlNoSuchEntityException(__($e->getMessage()), $e);
}
return $videoData;
}
}
Lets look at getVideos() function code. It gets all the records from the database table and returns the collection to the resolver.
Please make sure you insert some sample data in the database table
Let’s test it out. Execute following commands
php bin/magento cache:clean
php bin/magento setup:upgrade
GraphQL Mutation
Now, let’s edit our graphql schema to include mutation.
type Query {
getVideoData : [VideoData] @resolver (class:"\\Sjinnovation\\GraphqlDemo\\Model\\Resolver\\VideoDataResolver") @doc(description:"List of videos")
}
type VideoData {
video_id: Int @doc(description: "Video Id")
title: String @doc(description: "Video Title")
sub_title: String @doc(description: "Video Sub-title")
url: String @doc(description: "Video URL")
banner_url: String @doc(description: "Video Banner URL")
}
type Mutation {
createVideo(input: VideoInput!): VideoOutput @resolver (
class: "\\Sjinnovation\\GraphqlDemo\\Model\\Resolver\\CreateVideo") @doc(
description: "Insert new video")
}
input VideoInput {
title: String @doc(description: "Video Title")
sub_title: String @doc(description: "Video Sub-title")
url: String @doc(description: "Video URL")
banner_url: String @doc(description: "Video Banner URL")
}
type VideoOutput {
message: String @doc(description: "status message")
}
- Mutation operation is named as createVideo.
- VideoInput is a custom graphql input type having all the input variables
- VideoOutput is a custom graphql output type that sends the status message
As we can see for the above mutation, we have a new resolver to be created. So let’s create a CreateVideo resolver class at \Sjinnovation\GraphqlDemo\Model\Resolver
<?php
declare(strict_types=1);
namespace Sjinnovation\GraphqlDemo\Model\Resolver;
use Magento\Framework\GraphQl\Config\Element\Field;
use Magento\Framework\GraphQl\Exception\GraphQlInputException;
use Magento\Framework\GraphQl\Query\ResolverInterface;
use Magento\Framework\GraphQl\Schema\Type\ResolveInfo;
class CreateVideo implements ResolverInterface
{
/**
* @param Field $field
* @param \Magento\Framework\GraphQl\Query\Resolver\ContextInterface $context
* @param ResolveInfo $info
* @param array|null $value
* @param array|null $args
* @return array|\Magento\Framework\GraphQl\Query\Resolver\Value|mixed
* @throws GraphQlInputException
*/
private $dataProvider;
public function __construct(
\Sjinnovation\GraphqlDemo\Model\Resolver\DataProvider\Videos $dataProvider
) {
$this->dataProvider = $dataProvider;
}
public function resolve(
Field $field,
$context,
ResolveInfo $info,
array $value = null,
array $args = null)
{
try {
return $this->dataProvider->insertVideo($args['input']);
}
catch (\Exception $e) {
throw new GraphQlInputException(__($e->getMessage()));
}
}
}
Again, this resolver is going to implement ResolverInterface and override its resolve function. GraphQL input objects/variables are stored in $args parameter which is passed to insertVideo function of dataprovider class.
Let’s create insertVideo() function in dataprovider class.
<?php
namespace Sjinnovation\GraphqlDemo\Model\Resolver\DataProvider;
use Magento\Framework\Exception\NoSuchEntityException;
use Magento\Framework\GraphQl\Exception\GraphQlNoSuchEntityException;
use Magento\Framework\Exception\LocalizedException;
class Videos
{
protected $_videoFactory;
protected $_objectManager;
public function __construct(
\Sjinnovation\Videos\Model\ResourceModel\Videos\CollectionFactory $videoFactory,
\Magento\Framework\ObjectManagerInterface $objectManager
)
{
$this->_videoFactory = $videoFactory;
$this->_objectManager = $objectManager;
}
/**
* @params int $id
* this function return all the word of the day by id
**/
public function getVideos()
{
$videoData = [];
try {
$collection = $this->_videoFactory->create();
$videoData = $collection->getData();
} catch (NoSuchEntityException $e) {
throw new GraphQlNoSuchEntityException(__($e->getMessage()), $e);
}
return $videoData;
}
public function insertVideo($data)
{
if($this->validateURL($data['url']) && $this->validateURL($data['banner_url']))
{
if(is_array($data)) {
$video = $this->_objectManager->create('Sjinnovation\Videos\Model\Videos');
$video->setData($data)->save();
}
return ['message' => 'Success'];
}
else {
throw new LocalizedException(__('URL must be valid'));
}
}
public function validateURL($url) {
if(filter_var($url, FILTER_VALIDATE_URL))
return True;
else
return False;
}
}
First, we validate the required URLs. You can validate the required fields as per the requirements. Next, we create a new video model instance using object manager and set the data to model. And finally, we save the model which does the insert operation in the database table.
Let’s see the test results
So there you go! You have successfully created graphql API in the Magento development services for your custom Magento module.
You can also read about Magento Salesforce integration for any other help or assistance, contact our experts in Magento development services. We can certainly help you with all of your major and minor concerns.