How to create a GraphQL Mutation Endpoint for Magento 2.3
Lars Roettig
Posted on March 18, 2020
In my last Magento 2 tutorial, I showed how to build a basic GraphQL module with filtering.The primary purpose of GraphQL is to retrieve data (query), but every complete data exchange format needs a way to change server-based data (mutations).Therefore I want to show now how we can change data or create new pickup stores via the frontend.
Currently, the Magento 2 GraphQL Endpoint supports only access controls based on customers. This GraphQL will only allow a queryon the customer data if the customer’s token must proived in the header section.
Since I would like to show only exemplarily how such a thing could look, I did without access control!
Before we can start here, you can find the first module that we need ground for this tutorial.
How to create a GraphQL Endpoint for Magento 2.3
Create a new php file app/code/LarsRoettig/GraphQLStorePickup/Model/Resolver/CreatPickUpStore.php
This Class holds the logic for that endpoint is responsible for any GraphQL call that creates a new pickup store in the Database.Every Resolver Class is forced to implements Magento\Framework\GraphQl\Query\ResolverInterface
to work correctly.
<?php
declare(strict_types=1);
namespace LarsRoettig\GraphQLStorePickup\Model\Resolver;
use LarsRoettig\GraphQLStorePickup\Model\CreatePickUpStore as CreatPickUpStoreService;
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 CreatPickUpStore implements ResolverInterface
{
/**
* @var CreatPickUpStoreService
*/
private $creatPickUpStore;
/**
* @param CreatPickUpStore $creatPickUpStore
*/
public function __construct(CreatPickUpStoreService $creatPickUpStore)
{
$this->creatPickUpStore = $creatPickUpStore;
}
/**
* @inheritDoc
*/
public function resolve(Field $field, $context, ResolveInfo $info, array $value = null, array $args = null)
{
if (empty($args['input']) || !is_array($args['input'])) {
throw new GraphQlInputException(__('"input" value should be specified'));
}
return ['pick_up_store' => $this->creatPickUpStore->execute($args['input'])];
}
}
File app/code/LarsRoettig/GraphQLStorePickup/Model/CreatePickUpStore.php
:
The second step is to create a service class that will convert a given array to a pickup store and saves them in the database.A service class help us to have single small bussiness logic that can be used by differnt other php services.
<?php
declare(strict_types=1);
namespace LarsRoettig\GraphQLStorePickup\Model;
use LarsRoettig\GraphQLStorePickup\Api\Data\StoreInterface;
use LarsRoettig\GraphQLStorePickup\Api\Data\StoreInterfaceFactory;
use LarsRoettig\GraphQLStorePickup\Api\StoreRepositoryInterface;
use Magento\Framework\Api\DataObjectHelper;
use Magento\Framework\Exception\CouldNotSaveException;
use Magento\Framework\Exception\LocalizedException;
use Magento\Framework\GraphQl\Exception\GraphQlInputException;
class CreatePickUpStore
{
/**
* @var DataObjectHelper
*/
private $dataObjectHelper;
/**
* @var StoreRepositoryInterface
*/
private $storeRepository;
/**
* @var StoreInterfaceFactory
*/
private $storeFactory;
/**
* @param DataObjectHelper $dataObjectHelper
* @param StoreRepositoryInterface $storeRepository
* @param StoreInterfaceFactory $storeInterfaceFactory
*/
public function __construct(
DataObjectHelper $dataObjectHelper,
StoreRepositoryInterface $storeRepository,
StoreInterfaceFactory $storeInterfaceFactory
) {
$this->dataObjectHelper = $dataObjectHelper;
$this->storeRepository = $storeRepository;
$this->storeFactory = $storeInterfaceFactory;
}
/**
* @param array $data
* @return StoreInterface
* @throws GraphQlInputException
*/
public function execute(array $data): StoreInterface
{
try {
$this->vaildateData($data);
$store = $this->saveStore($this->createStore($data));
} catch (\Exception $e) {
throw new GraphQlInputException(__($e->getMessage()));
}
return $store;
}
/**
* Guard function to handle bad request.
* @param array $data
* @throws LocalizedException
*/
private function vaildateData(array $data)
{
if (!isset($data[StoreInterface::NAME])) {
throw new LocalizedException(__('Name must be set'));
}
}
/**
* Persists the given store in the data base.
* +
* @param StoreInterface $store
* @return StoreInterface
* @throws CouldNotSaveException
*/
private function saveStore(StoreInterface $store): StoreInterface
{
$this->storeRepository->save($store);
return $store;
}
/**
* Create a store dto by given data array.
*
* @param array $data
* @return StoreInterface
* @throws CouldNotSaveException
*/
private function createStore(array $data): StoreInterface
{
/** @var StoreInterface $store */
$store = $this->storeFactory->create();
$this->dataObjectHelper->populateWithArray(
$store,
$data,
StoreInterface::class
);
return $store;
}
}
File app/code/LarsRoettig/GraphQLStorePickup/etc/schema.graphqls
This need to be added to the file:
type Mutation {
createPickUpStores(input: PickUpStoreInput!): PickUpStoreOutput @resolver(class: "\\LarsRoettig\\GraphQLStorePickup\\Model\\Resolver\\CreatPickUpStore") @doc(description: "Create a new pickup store")
}
type PickUpStoreOutput {
pick_up_store: PickUpStore!
}
input PickUpStoreInput {
name: String @doc(description: "")
street: String @doc(description: "")
street_num: Int @doc(description: "")
city: String @doc(description: "")
postcode: String @doc(description: "")
latitude:Float @doc(description: "")
longitude: Float @doc(description: "")
}
Full File:
type Query {
pickUpStores(
filter: PickUpStoresFilterInput @doc(description: "")
pageSize: Int = 5 @doc(description: "How many items should show on the page")
currentPage: Int = 1 @doc(description: "Allows to ussing paging it start with 1")
):PickUpStoresOutput @resolver(class: "\\LarsRoettig\\GraphQLStorePickup\\Model\\Resolver\\PickUpStores") @doc(description: "Allow to query for a pickup store.")
}
type Mutation {
createPickUpStores(input: PickUpStoreInput!): PickUpStoreOutput @resolver(class: "\\LarsRoettig\\GraphQLStorePickup\\Model\\Resolver\\CreatPickUpStore") @doc(description: "Create a new pickup store")
}
type PickUpStoreOutput {
pick_up_store: PickUpStore!
}
input PickUpStoreInput {
name: String @doc(description: "")
street: String @doc(description: "")
street_num: Int @doc(description: "")
city: String @doc(description: "")
postcode: String @doc(description: "")
latitude:Float @doc(description: "")
longitude: Float @doc(description: "")
}
input PickUpStoresFilterInput {
name: FilterTypeInput @doc(description: "")
postcode: FilterTypeInput @doc(description: ""),
street: FilterTypeInput @doc(description: ""),
street_num: FilterTypeInput @doc(description: ""),
city: FilterTypeInput @doc(description: ""),
latitude:FilterTypeInput @doc(description: ""),
longitude: FilterTypeInput @doc(description: ""),
or: PickUpStoresFilterInput
}
type PickUpStoresOutput {
total_count: Int @doc(description: "")
items: [PickUpStore] @doc(description: "")
}
type PickUpStore {
entity_id: Int @doc(description: ""),
name: String @doc(description: ""),
street: String @doc(description: ""),
street_num: Int @doc(description: ""),
city: String @doc(description: ""),
postcode: String @doc(description: ""),
latitude:Float @doc(description: ""),
longitude: Float @doc(description: ""),
}
3. Installation:
bin/magento module:enable LarsRoettig_GraphQLStorePickup
bin/magento setup:db-declaration:generate-whitelist --module-name=LarsRoettig_GraphQLStorePickup
bin/magento setup:upgrade
The repo bramch can founded at Github:
https://github.com/larsroettig/module-graphqlstorepickup/tree/2.0-develop
How to call your GraphQL Endpoint
Attention the Url https://your\_domain.test/graphql work only with an valid GraphQL-Request!
GraphQL-Mutation:
mutation {
createPickUpStores(
input: {
name: "Mustation Store"
street: "sweswq"
street_num: 12
postcode: "83059"
latitude: 22.3
longitude:22.3
}
)
{
pick_up_store {
name
}
}
}
(This article was posted to my blog at https://larsroettig.dev. You can read it online by clicking here.)
Posted on March 18, 2020
Join Our Newsletter. No Spam, Only the good stuff.
Sign up to receive the latest update from our blog.
Related
November 30, 2024