Если вы когда-нибудь ловили себя на мысли, что REST API начинает раздражать — слишком много запросов, лишние данные, версионирование — то GraphQL может стать вашим спасательным кругом. Это не просто очередная модная штука, а реальный способ упростить жизнь и себе, и фронтендерам. В этой статье я расскажу, как использовать GraphQL в PHP-проектах, без занудства и сложных терминов. Поехали!

Digital-студия WNDER

Что такое GraphQL и почему он вообще нужен

GraphQL — это язык запросов к API. Придумали его в Facebook, чтобы решить проблему избыточности данных и множества запросов. Суть простая: вместо того чтобы получать готовый ответ от сервера, вы сами описываете, что хотите получить. Сервер возвращает ровно то, что вы просили, и ничего лишнего.

Представьте, что вы идёте в ресторан и говорите официанту: "Принесите мне борщ, но без сметаны, и хлеб, но только тёмный". В REST вы бы заказали комплексный обед и получили всё подряд, а в GraphQL — только то, что нужно. И это очень удобно.

Для PHP это особенно актуально, потому что PHP — один из самых популярных языков для бэкенда, и интеграция GraphQL открывает новые горизонты.

Как GraphQL работает на практике

GraphQL работает через схему (schema), которая описывает все возможные типы данных и операции. Есть два основных типа операций: запросы (query) и мутации (mutation). Запросы — это чтение данных, мутации — изменение.

Клиент отправляет POST-запрос на сервер, содержащий текст запроса на специальном языке. Сервер обрабатывает его, выполняет нужные функции и возвращает JSON-ответ. Всё просто.

В PHP для работы с GraphQL есть несколько библиотек, самая популярная — graphql-php. Она позволяет создать схему, привязать её к вашему коду и обрабатывать запросы.

Установка и настройка GraphQL в PHP

Для начала установите библиотеку через Composer. Если не знаете, что это — это менеджер пакетов для PHP, который упрощает установку зависимостей. Выполните команду:

composer require webonyx/graphql-php

Теперь создадим простой пример. Представьте, что у нас есть блог с постами и авторами. Мы хотим получать список постов и каждого автора. Создадим файл schema.php, где определим типы и обработчики.

require_once 'vendor/autoload.php';

use GraphQL\Type\Definition\ObjectType;
use GraphQL\Type\Definition\Type;
use GraphQL\Type\Schema;
use GraphQL\GraphQL;

// Определяем тип Author
$authorType = new ObjectType([
    'name' => 'Author',
    'fields' => [
        'id' => Type::int(),
        'name' => Type::string(),
    ]
]);

// Определяем тип Post
$postType = new ObjectType([
    'name' => 'Post',
    'fields' => [
        'id' => Type::int(),
        'title' => Type::string(),
        'content' => Type::string(),
        'author' => $authorType, // вложенный тип
    ]
]);

// Определяем тип Query (точка входа для запросов)
$queryType = new ObjectType([
    'name' => 'Query',
    'fields' => [
        'posts' => [
            'type' => Type::listOf($postType),
            'resolve' => function () {
                // Здесь вы получаете данные из БД или другого источника
                return [
                    [
                        'id' => 1,
                        'title' => 'Первая запись',
                        'content' => 'Содержимое первой записи',
                        'author' => ['id' => 1, 'name' => 'Иван Петров']
                    ],
                    [
                        'id' => 2,
                        'title' => 'Вторая запись',
                        'content' => 'Содержимое второй записи',
                        'author' => ['id' => 2, 'name' => 'Мария Смирнова']
                    ]
                ];
            }
        ]
    ]
]);

// Создаём схему
$schema = new Schema([
    'query' => $queryType
]);

// Обрабатываем запрос
$rawInput = file_get_contents('php://input');
$input = json_decode($rawInput, true);
$query = $input['query'];
$result = GraphQL::executeQuery($schema, $query);
$output = $result->toArray();

header('Content-Type: application/json');
echo json_encode($output);

Теперь клиент может отправить запрос:

fetch('/graphql', {
    method: 'POST',
    headers: { 'Content-Type': 'application/json' },
    body: JSON.stringify({
        query: `
            query {
                posts {
                    title
                    author {
                        name
                    }
                }
            }
        `
    })
});

И получит только нужные поля. Удобно, правда?

Мутации: изменение данных через GraphQL

Чтение — это хорошо, но что насчёт создания или обновления данных? Для этого есть мутации. Они работают аналогично запросам, но с побочными эффектами. Например, создадим мутацию для добавления нового поста.

$mutationType = new ObjectType([
    'name' => 'Mutation',
    'fields' => [
        'addPost' => [
            'type' => $postType,
            'args' => [
                'title' => Type::nonNull(Type::string()),
                'content' => Type::nonNull(Type::string()),
                'authorId' => Type::nonNull(Type::int()),
            ],
            'resolve' => function ($root, $args) {
                // Здесь вы добавляете запись в базу данных
                // Возвращаем созданный объект
                return [
                    'id' => 3,
                    'title' => $args['title'],
                    'content' => $args['content'],
                    'author' => ['id' => $args['authorId'], 'name' => 'Иван Петров']
                ];
            }
        ]
    ]
]);

$schema = new Schema([
    'query' => $queryType,
    'mutation' => $mutationType
]);

Мутация вызывается так:

fetch('/graphql', {
    method: 'POST',
    headers: { 'Content-Type': 'application/json' },
    body: JSON.stringify({
        query: `
            mutation {
                addPost(title: "Новый пост", content: "Текст поста", authorId: 1) {
                    id
                    title
                }
            }
        `
    })
});

В ответ вы получите данные созданного поста — id и title. Очень удобно для фронтенда.

Советы и лайфхаки для работы с GraphQL в PHP

Теперь несколько практических советов, которые помогут вам избежать граблей.

Правило: всегда валидируйте входные данные. GraphQL автоматически проверяет типы, но не проверяет бизнес-логику. Например, если пользователь передаёт отрицательное значение, это может пройти. Используйте собственные проверки.

Вот ещё несколько важных моментов:

  • Используйте контейнеры зависимостей (например, PHP-DI или Symfony DI), чтобы легко подключать сервисы к resolve-функциям.
  • Подумайте о кэшировании схемы. Создание схемы каждый раз — затратно. Храните её в кэше (APCu, Redis).
  • Не забывайте про N+1 проблему. Если у вас есть список постов и для каждого поста вы запрашиваете автора, без правильного подхода это приведёт к множеству запросов к БД. Используйте DataLoader или групповые выборки.

Сравним REST и GraphQL:

Критерий REST GraphQL
Количество запросов Часто много, приходится делать несколько запросов Один запрос на нужные данные
Передача лишних данных Часто приходит много лишнего Только то, что запросили
Гибкость Нужно создавать новые эндпоинты Клиент сам формирует запрос
Версионирование Часто нужно версионировать API Не требуется, схема эволюционирует

Что в итоге

GraphQL — это мощный инструмент, который отлично вписывается в PHP-экосистему. Он позволяет создавать гибкие API, которые легко поддерживать и расширять. Главное — правильно спроектировать схему и не забывать про производительность.

Начните с малого: добавьте GraphQL к одному из ваших проектов, и вы почувствуете разницу. А если появятся вопросы — загляните в документацию graphql-php, там всё подробно описано.

Помните: не бойтесь экспериментировать. Программирование — это творчество, и GraphQL открывает новые возможности для вашего кода.

Студия WNDER