GraphQL API с PHP: пошаговый туториал на практике
GraphQL — это язык запросов для API, который позволяет клиентам получать только те данные, которые им действительно нужны. В отличие от REST, где каждый эндпоинт возвращает фиксированную структуру, GraphQL даёт гибкость и эффективность. В этом туториале мы создадим полноценный GraphQL API на PHP с нуля — от установки библиотек до обработки запросов и мутаций.
Почему GraphQL и PHP — отличная пара?
PHP остаётся одним из самых популярных языков для серверной разработки. С помощью библиотеки webonyx/graphql-php вы можете легко интегрировать GraphQL в любой проект — от простого блога до сложной CRM. Основные преимущества:
- Гибкость запросов — клиент сам решает, какие поля получать.
- Одна точка входа — вместо множества эндпоинтов один
/graphql. - Строгая типизация — схема определяет все типы и связи.
- Удобство для фронтенда — React, Vue и другие фреймворки легко работают с GraphQL.
Пошаговая реализация GraphQL API на PHP
1. Установка и настройка окружения
Для начала создадим новый проект и установим основную библиотеку через Composer:
composer require webonyx/graphql-php
Также нам понадобится PSR-7 совместимый HTTP-обработчик. Используем guzzlehttp/psr7 и nyholm/psr7-server:
composer require guzzlehttp/psr7 nyholm/psr7-server
Создадим базовую структуру папок:
project/
├── src/
│ ├── Schema/
│ ├── Resolvers/
│ └── Types/
├── public/
│ └── index.php
├── vendor/
└── composer.json
2. Определение схемы GraphQL
Схема — это сердце GraphQL API. Она описывает типы данных и доступные операции. Создадим файл src/Schema/Schema.php:
<?php
namespace App\Schema;
use GraphQL\Type\Definition\ObjectType;
use GraphQL\Type\Definition\Type;
use GraphQL\Type\Schema as GraphQLSchema;
class Schema
{
public static function build(): GraphQLSchema
{
// Тип "User"
$userType = new ObjectType([
'name' => 'User',
'fields' => [
'id' => Type::int(),
'name' => Type::string(),
'email' => Type::string(),
]
]);
// Тип "Query" — корневой запрос
$queryType = new ObjectType([
'name' => 'Query',
'fields' => [
'user' => [
'type' => $userType,
'args' => [
'id' => Type::nonNull(Type::int())
],
'resolve' => function ($root, $args) {
// Здесь будет резолвер
return UserResolver::getUser($args['id']);
}
],
'users' => [
'type' => Type::listOf($userType),
'resolve' => function () {
return UserResolver::getAllUsers();
}
]
]
]);
// Тип "Mutation" — корневая мутация
$mutationType = new ObjectType([
'name' => 'Mutation',
'fields' => [
'createUser' => [
'type' => $userType,
'args' => [
'name' => Type::nonNull(Type::string()),
'email' => Type::nonNull(Type::string())
],
'resolve' => function ($root, $args) {
return UserResolver::createUser($args['name'], $args['email']);
}
]
]
]);
return new GraphQLSchema([
'query' => $queryType,
'mutation' => $mutationType
]);
}
}
3. Реализация резолверов
Резолверы — это функции, которые возвращают данные для каждого поля. Создадим src/Resolvers/UserResolver.php:
<?php
namespace App\Resolvers;
class UserResolver
{
private static $users = [
1 => ['id' => 1, 'name' => 'Иван Петров', 'email' => 'ivan@example.com'],
2 => ['id' => 2, 'name' => 'Мария Сидорова', 'email' => 'maria@example.com'],
];
public static function getUser(int $id): ?array
{
return self::$users[$id] ?? null;
}
public static function getAllUsers(): array
{
return array_values(self::$users);
}
public static function createUser(string $name, string $email): array
{
$newId = count(self::$users) + 1;
self::$users[$newId] = [
'id' => $newId,
'name' => $name,
'email' => $email
];
return self::$users[$newId];
}
}
4. Точка входа — обработка запросов
Теперь создадим главный файл public/index.php, который будет принимать HTTP-запросы и возвращать ответы GraphQL:
<?php
require_once __DIR__ . '/../vendor/autoload.php';
use App\Schema\Schema;
use GraphQL\GraphQL;
use GraphQL\Error\Debug;
use Nyholm\Psr7\Factory\Psr17Factory;
use Nyholm\Psr7Server\ServerRequestCreator;
// Создаём PSR-7 запрос из глобальных переменных
$psr17Factory = new Psr17Factory();
$creator = new ServerRequestCreator(
$psr17Factory,
$psr17Factory,
$psr17Factory,
$psr17Factory
);
$request = $creator->fromGlobals();
// Получаем тело запроса
$body = json_decode((string)$request->getBody(), true);
$query = $body['query'] ?? '';
$variables = $body['variables'] ?? null;
// Строим схему и выполняем запрос
try {
$schema = Schema::build();
$result = GraphQL::executeQuery(
$schema,
$query,
null,
null,
$variables
);
$output = $result->toArray(Debug::INCLUDE_DEBUG_MESSAGE);
} catch (\Exception $e) {
$output = [
'errors' => [
['message' => $e->getMessage()]
]
];
}
// Отправляем JSON-ответ
header('Content-Type: application/json');
echo json_encode($output);
Тестирование API
Запустите встроенный сервер PHP:
php -S localhost:8000 -t public/
Теперь можно отправлять запросы. Пример запроса через curl:
curl -X POST http://localhost:8000/ \
-H "Content-Type: application/json" \
-d '