PHP - Creating GraphQL APIs with PHP

Introduction

GraphQL is a modern API query language developed by Facebook that provides a flexible and efficient way for clients to request data from a server. Unlike REST APIs, where each endpoint returns a predefined set of data, GraphQL allows clients to specify exactly what data they need. This reduces unnecessary data transfer and improves application performance.

PHP developers can build GraphQL APIs using libraries such as webonyx/graphql-php, Lighthouse (for Laravel), or Overblog GraphQL Bundle (for Symfony). GraphQL is widely used in web applications, mobile apps, dashboards, and enterprise systems where efficient data retrieval is important.

For example, an e-commerce application can use a GraphQL API to fetch product details, customer information, reviews, and inventory status in a single request instead of calling multiple REST endpoints.


Why Use GraphQL Instead of REST?

Traditional REST APIs expose multiple endpoints.

Example:

  • /users

  • /products

  • /orders

  • /categories

To display a user's dashboard, the frontend may need to call several endpoints one after another.

GraphQL uses a single endpoint.

Example:

/graphql

The client sends a query specifying exactly what information it wants.

Benefits include:

  • Reduced network requests

  • Faster response times

  • Flexible data retrieval

  • Easier API evolution

  • Better support for mobile applications

  • Reduced over-fetching and under-fetching


Installing GraphQL in PHP

One of the most popular GraphQL libraries for PHP is:

webonyx/graphql-php

Install it using Composer.

composer require webonyx/graphql-php

This package provides everything required to create GraphQL schemas, queries, mutations, and execute requests.


Understanding GraphQL Components

A GraphQL API consists of several important components.

1. Schema

The schema defines the structure of the API.

It specifies:

  • Data types

  • Available queries

  • Available mutations

  • Relationships

Example schema concept:

Product
    id
    name
    price

Customer
    id
    name
    email

Order
    id
    total

The schema acts as a contract between the server and clients.


2. Types

Types define objects in the GraphQL API.

Example:

Product

ID
Name
Price
Description
Category

PHP representation:

ProductType

Each field has a specific data type.

ID

String

Int

Float

Boolean

Custom object types can also be created.


3. Queries

Queries retrieve data.

Example GraphQL query:

{
  products {
    id
    name
    price
  }
}

Unlike REST, only requested fields are returned.

Example response:

{
  "data": {
    "products": [
      {
        "id":1,
        "name":"Laptop",
        "price":55000
      }
    ]
  }
}

4. Mutations

Mutations perform operations like:

  • Insert

  • Update

  • Delete

Example:

mutation {
  createProduct(
    name:"Phone",
    price:25000
  ){
    id
    name
  }
}

Response:

{
  "data":{
    "createProduct":{
      "id":12,
      "name":"Phone"
    }
  }
}

5. Resolvers

Resolvers contain the actual PHP logic.

Whenever a query requests data, GraphQL calls a resolver.

Example:

GraphQL Query

↓

Resolver

↓

Database

↓

Response

Example resolver:

function getProducts()
{
    return Product::all();
}

Resolvers can:

  • Read database records

  • Validate data

  • Call APIs

  • Process business logic


Building a Simple Product API

Suppose a store has products.

Database table:

products
id name price
1 Laptop 55000
2 Phone 25000

The GraphQL schema defines:

Product

id

name

price

Clients can request:

{
  products{
    id
    name
    price
  }
}

The PHP resolver fetches records.

$products = Product::all();

The response contains only requested fields.


Fetching a Single Product

GraphQL query:

{
  product(id:1){
    name
    price
  }
}

Resolver:

function getProduct($id)
{
    return Product::find($id);
}

Response:

{
 "data":{
   "product":{
      "name":"Laptop",
      "price":55000
   }
 }
}

Nested Queries

GraphQL supports nested objects.

Example:

Customer

Orders

Products

Single query:

{
  customer(id:2){
    name

    orders{
      total

      products{
        name
        price
      }
    }
  }
}

Instead of multiple REST calls, everything is fetched together.


Query Arguments

Queries accept parameters.

Example:

{
 products(category:"Electronics"){
    name
    price
 }
}

PHP resolver:

function getProducts($category)
{
   return Product::where(
      "category",
      $category
   )->get();
}

Arguments help filter data.


Pagination

Large datasets should not be returned all at once.

Example:

{
 products(page:1, limit:10){
    id
    name
 }
}

PHP:

Product::limit(10)
       ->offset(0)
       ->get();

Pagination improves performance.


Sorting

Example:

{
 products(sort:"price"){
    name
    price
 }
}

Result:

Phone

Tablet

Laptop

Sorting helps organize data.


Filtering

Example:

{
 products(
   category:"Electronics",
   priceGreaterThan:10000
 ){
    name
    price
 }
}

Filtering returns only relevant records.


Creating Data with Mutations

Example:

mutation{

createProduct(

name:"Keyboard",

price:1200

){

id

name

}
}

PHP:

$product = Product::create([
"name"=>"Keyboard",
"price"=>1200
]);

Response:

{
 "data":{
   "createProduct":{
      "id":15,
      "name":"Keyboard"
   }
 }
}

Updating Records

Mutation:

mutation{

updateProduct(

id:2,

price:28000

){

id

price

}
}

PHP:

$product = Product::find(2);

$product->price = 28000;

$product->save();

Deleting Records

Mutation:

mutation{

deleteProduct(id:3)

}

PHP:

Product::destroy(3);

GraphQL Variables

Instead of hardcoding values:

id:5

Variables are used.

Query:

query Product($id:ID!){

product(id:$id){

name

price

}
}

Variables:

{
"id":5
}

Variables improve security and code reuse.


Authentication

GraphQL APIs should verify user identity before processing sensitive requests.

Common authentication methods include:

  • JSON Web Tokens (JWT)

  • OAuth 2.0

  • Laravel Sanctum

  • Laravel Passport

  • Session-based authentication

Example workflow:

User Login

↓

Token Generated

↓

Client Stores Token

↓

Every GraphQL Request Includes Token

↓

Server Validates Token

Unauthorized requests should be rejected.


Authorization

Authentication confirms who the user is, while authorization determines what they are allowed to do.

Example:

  • Customers can view only their own orders.

  • Administrators can create, update, and delete products.

  • Vendors can manage only their own inventory.

Resolvers should verify permissions before executing operations.


Error Handling

GraphQL returns errors in a structured format.

Example:

{
  "errors":[
    {
      "message":"Product not found"
    }
  ]
}

Developers should avoid exposing sensitive information such as SQL queries or server paths in error messages.


Performance Optimization

GraphQL APIs can suffer from performance issues if not optimized.

Common techniques include:

DataLoader

DataLoader batches and caches database requests to prevent the "N+1 query problem."

Without DataLoader:

100 Products

↓

100 Database Queries

With DataLoader:

100 Products

↓

1 Optimized Database Query

Query Complexity Limits

Restrict deeply nested or expensive queries to prevent abuse.

Response Caching

Cache frequently requested data using tools like Redis or Memcached to reduce database load.

Pagination

Always paginate large collections instead of returning all records.

Database Indexing

Ensure frequently filtered or sorted columns are indexed for faster query execution.


GraphQL Security Best Practices

  • Validate all user input before processing.

  • Implement authentication and authorization for protected operations.

  • Disable unnecessary introspection in production if appropriate.

  • Limit query depth and complexity to prevent denial-of-service attacks.

  • Use HTTPS to encrypt data in transit.

  • Sanitize data before storing it in the database.

  • Log suspicious requests and monitor API usage.

  • Apply rate limiting to prevent abuse.


GraphQL vs REST

Feature GraphQL REST
Endpoints Single endpoint Multiple endpoints
Data Fetching Client specifies required fields Server returns predefined data
Over-fetching Avoided Common
Under-fetching Avoided Possible
Versioning Typically unnecessary due to schema evolution Often requires API versioning
Nested Data Supported in one request Usually requires multiple requests
Flexibility High Moderate

Real-World Applications

GraphQL APIs built with PHP are commonly used in:

  • E-commerce platforms for products, customers, carts, and orders.

  • Social networking applications to efficiently retrieve user profiles, posts, comments, and followers.

  • Learning Management Systems (LMS) to manage courses, lessons, quizzes, and student progress.

  • Content Management Systems (CMS) for articles, categories, authors, and media assets.

  • Banking and financial dashboards that aggregate account details, transactions, and analytics.

  • Healthcare portals for securely accessing patient records, appointments, prescriptions, and reports.

  • Enterprise Resource Planning (ERP) systems for inventory, procurement, sales, and employee management.

  • Mobile applications that require optimized data usage and reduced network requests.


Conclusion

GraphQL provides a powerful and flexible approach to building APIs in PHP by allowing clients to request only the data they need through a single endpoint. With well-designed schemas, efficient resolvers, secure authentication, optimized queries, and proper error handling, PHP developers can create scalable, high-performance APIs for modern web and mobile applications. As applications grow in complexity, GraphQL offers significant advantages over traditional REST APIs by improving efficiency, reducing network traffic, and simplifying data access across multiple interconnected resources.