Encodera

Спасибо, что читаете!

Пожертвуйте сайту, мы стараемся ради вас.

Оглавление

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 написано с одной обратной косой чертой вместо двух.

Спасибо, что читаете!

Пожертвуйте сайту, мы стараемся ради вас.