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.)
Top comments (0)