Introduction to GraphQL and PHP
GraphQL is a query language for APIs developed by Facebook that allows clients to request only the data they actually need. Unlike REST, where each endpoint returns a fixed data structure, GraphQL provides flexibility and efficiency. If you work with PHP and want to implement a modern API, this tutorial is for you.
In this guide, we will create a simple but functional GraphQL API using the webonyx/graphql-php library. You will learn how to install dependencies, define a schema, types, resolvers, and handle queries. Code examples will help you get started quickly.
1. Environment Setup and Dependency Installation
First, make sure you have PHP version 7.4 or higher installed and Composer — the dependency manager for PHP. If Composer is not yet installed, download it from the official website.
Create a new project and install the webonyx/graphql-php library:
mkdir graphql-php-tutorialcd graphql-php-tutorialcomposer init --name="myapp/graphql-demo" --type="project" --no-interactioncomposer require webonyx/graphql-phpAfter installation, the vendor directory and composer.json file will appear in the project folder. Also create an index.php file — all our code will be in it.
Additionally, for convenient work with HTTP requests, install laminas/laminas-diactoros (a popular PSR-7 implementation) and laminas/laminas-httphandlerrunner:
composer require laminas/laminas-diactoroscomposer require laminas/laminas-httphandlerrunner2. Defining the GraphQL Schema and Types
The heart of any GraphQL API is the schema. It describes what data is available and how it can be queried. In our example, we will create a simple "User" and "Post" model.
First, define the types using the GraphQL\\Type\\Definition\\ObjectType class. Create a schema.php file (or add the code directly to index.php).
<?phprequire_once __DIR__ . '/vendor/autoload.php';
use GraphQL\\Type\\Definition\\ObjectType;use GraphQL\\Type\\Definition\\Type;use GraphQL\\Type\\Schema;use GraphQL\\GraphQL;
// Define the User type$userType = new ObjectType([ 'name' => 'User', 'description' => 'Represents a system user', 'fields' => [ 'id' => Type::int(), 'name' => Type::string(), 'email' => Type::string(), ]]);
// Define the Post type$postType = new ObjectType([ 'name' => 'Post', 'description' => 'User post', 'fields' => [ 'id' => Type::int(), 'title' => Type::string(), 'content' => Type::string(), 'author' => $userType, // Relationship with user ]]);Note: we use Type::int() and Type::string() — these are built-in scalar GraphQL types. The author field references another object type, which allows building nested queries.
3. Creating Resolvers and Mock Data
Resolvers are functions that return data for each field. In the simplest case, we can use mock data (arrays).
Let's add resolvers for the root Query type. It is through this that clients will receive data.
// Mock data$users = [ 1 => ['id' => 1, 'name' => 'Ivan Petrov', 'email' => 'ivan@example.com'], 2 => ['id' => 2, 'name' => 'Maria Smirnova', 'email' => 'maria@example.com'],];
$posts = [ 1 => ['id' => 1, 'title' => 'First Post', 'content' => 'Text of the first post', 'author_id' => 1],