GraphQL
GraphQL — второй вид API в Magento. В отличие от REST, здесь один адрес — /graphql, а клиент сам перечисляет в запросе нужные поля и получает ровно их. GraphQL используют витрины на JavaScript и мобильные приложения. Модуль добавляет в общую схему свои запросы и пишет для них класс, возвращающий данные, — резолвер.
Где лежат файлы
| Файл | Что в нём |
|---|---|
etc/schema.graphqls | Описание запросов и типов |
Model/Resolver/Reviews.php | Резолвер — класс, который возвращает данные |
Оба файла создают вручную.
app/code/Acme/Hello/
├── Model/
│ └── Resolver/
│ └── Reviews.php новый файл
└── etc/
├── module.xml изменён
└── schema.graphqls новый файлВ module.xml добавьте в раздел sequence модуль Magento_GraphQl и выполните bin/magento setup:upgrade.
Схема
# app/code/Acme/Hello/etc/schema.graphqls
type Query {
helloReviews(productId: Int!): [HelloReview] @resolver(class: "Acme\\Hello\\Model\\Resolver\\Reviews")
}
type HelloReview {
author: String
rating: Int
}Файл добавляет в общий тип Query запрос helloReviews с обязательным аргументом productId. Запрос возвращает список объектов типа HelloReview с двумя полями. Директива @resolver называет класс, который вернёт данные; обратная косая черта в имени класса удваивается.
Резолвер
// app/code/Acme/Hello/Model/Resolver/Reviews.php
namespace Acme\Hello\Model\Resolver;
use Acme\Hello\Api\ReviewRepositoryInterface;
use Magento\Framework\Api\SearchCriteriaBuilder;
use Magento\Framework\GraphQl\Config\Element\Field;
use Magento\Framework\GraphQl\Query\ResolverInterface;
use Magento\Framework\GraphQl\Schema\Type\ResolveInfo;
class Reviews implements ResolverInterface
{
public function __construct(
private ReviewRepositoryInterface $reviewRepository,
private SearchCriteriaBuilder $criteriaBuilder,
) {}
public function resolve(Field $field, $context, ResolveInfo $info, ?array $value = null, ?array $args = null)
{
$criteria = $this->criteriaBuilder
->addFilter('product_id', (int) $args['productId'])
->create();
$reviews = [];
foreach ($this->reviewRepository->getList($criteria)->getItems() as $review) {
$reviews[] = [
'author' => $review->getAuthor(),
'rating' => $review->getRating(),
];
}
return $reviews;
}
}Аргументы запроса приходят в массиве $args. Резолвер находит отзывы через репозиторий и возвращает массив, ключи которого совпадают с именами полей типа HelloReview.
Проверка
bin/magento cache:clean
curl -X POST http://shop.test/graphql \
-H "Content-Type: application/json" \
-d '{"query": "{ helloReviews(productId: 1) { author rating } }"}'Сервер ответит объектом JSON, в котором под ключом data.helloReviews лежит список авторов и оценок отзывов о товаре с номером 1. Если убрать из запроса rating, в ответе останутся только авторы.
Сам запрос без обёртки выглядит так:
{
helloReviews(productId: 1) {
author
rating
}
}Удобнее отправлять запросы из отдельной программы для GraphQL: она читает схему магазина и подсказывает поля.
Запросы и изменения
| Тип в схеме | Для чего |
|---|---|
Query | Чтение данных |
Mutation | Изменение: создать, обновить, удалить |
Изменение описывают так же — полем в типе Mutation с директивой @resolver. Данные для него обычно передают одним аргументом входного типа, который объявляют словом input.
Ошибки
Если запрос нельзя выполнить, резолвер бросает исключение из пространства имён Magento\Framework\GraphQl\Exception, например GraphQlInputException для неверных аргументов. Клиент получит сообщение в разделе errors ответа.
Частая ошибка
Схему изменили, а сервер отвечает, что поля helloReviews не существует. Собранная схема кешируется: после каждой правки schema.graphqls выполняйте bin/magento cache:clean. Вторая причина — имя класса в @resolver написано с одной обратной косой чертой вместо двух.