Skip to content
Muhammet Şafak
tr
Web Development 4 min read

After REST: Trying Out GraphQL

While solving a real over-fetching problem with GraphQL, I weigh where REST is still sufficient and where GraphQL actually makes sense.


GraphQL had been on my radar for years, but I kept putting it off with the “REST already works” feeling. Mid-year on one project I ran into a concrete problem, and solving that problem actually required giving GraphQL a real try. Now I’m writing up both what I found and where REST still holds up better.

The concrete problem: too many requests for a single mobile screen

An app screen displayed: a user profile, their last three orders, and the product names within each order. With REST we were making three separate endpoint calls to assemble this:

  1. GET /api/user/42 → profile
  2. GET /api/users/42/orders?limit=3 → orders
  3. GET /api/orders/{id}/items for each order (at least three more requests)

Five to six HTTP requests in total. Each one waits for a response, each one involves JSON parsing. Network latency was slowing down the screen’s load time noticeably.

On top of that, every endpoint was bringing back more data than we needed. The order list included order date, payment method, shipping address — none of which appeared on the screen. We had to fetch, transfer, and parse all that extra data anyway.

REST has standard solutions for these problems: eager loading via an include parameter, custom endpoints, API Gateway aggregation… But all of those put extra burden on the server side, and every new screen requirement calls for a new endpoint or a new parameter arrangement.

What GraphQL is

GraphQL (Graph Query Language) is an API query language developed by Facebook and open-sourced in 2015. It is not a protocol like REST; it is a query mechanism where the client specifies exactly what it wants.

A single endpoint (/graphql) returns different data depending on the query the client sends:

query UserDashboard($userId: ID!) {
  user(id: $userId) {
    name
    email
    orders(limit: 3) {
      id
      status
      items {
        productName
      }
    }
  }
}

This single query fetches in one round-trip what five or six REST requests used to cover. The client declares exactly which fields it needs; the server returns only those fields.

Setting up GraphQL in Laravel with PHP

The rebing/graphql-laravel package makes standing up a GraphQL server in Laravel relatively straightforward:

composer require rebing/graphql-laravel

Type definition:

<?php

use Rebing\GraphQL\Support\Type as GraphQLType;
use GraphQL\Type\Definition\Type;

class UserType extends GraphQLType
{
    protected $attributes = [
        'name'  => 'User',
        'model' => \App\Models\User::class,
    ];

    public function fields(): array
    {
        return [
            'id'    => ['type' => Type::nonNull(Type::id())],
            'name'  => ['type' => Type::nonNull(Type::string())],
            'email' => ['type' => Type::nonNull(Type::string())],
        ];
    }
}

Query definition:

<?php

use Rebing\GraphQL\Support\Query;
use GraphQL\Type\Definition\Type;
use GraphQL\Type\Definition\ResolveInfo;

class UserQuery extends Query
{
    protected $attributes = ['name' => 'user'];

    public function type(): Type
    {
        return GraphQL::type('User');
    }

    public function args(): array
    {
        return [
            'id' => ['type' => Type::nonNull(Type::id())],
        ];
    }

    public function resolve($root, array $args, $context, ResolveInfo $resolveInfo)
    {
        return User::findOrFail($args['id']);
    }
}

The N+1 problem: GraphQL’s classic trap

The moment you start using GraphQL, the N+1 problem hits you in the face. When you request a user’s orders and then the items within each order, the resolver can open a separate database query for every single order.

In the PHP ecosystem there are dataloader libraries to address this. Tools like luckydonald/php-odata-query or overblog/dataloader-php batch the requests. What you solved with with() in REST/Eloquent needs more deliberate management in GraphQL.

An honest comparison

When GraphQL makes sense:

  • Multiple clients (web, mobile, third-party) share the same API and each has different data needs.
  • Over-fetching and under-fetching are creating a real performance problem.
  • You want to open new queries for rapidly changing UI requirements without touching the backend.

Where REST still holds up better:

  • There is a single client and the data requirements are relatively predictable.
  • The workload is predominantly simple CRUD operations.
  • Caching is critical: REST endpoints cache easily with HTTP caching, while GraphQL POST requests make that considerably more painful.
  • The team is not yet mature enough to invest in the GraphQL toolchain.

At the end of this experiment I decided to reach for GraphQL specifically in the places where over-fetching is a genuine problem, rather than adopting it everywhere. REST and GraphQL can coexist quite comfortably within the same service.

Tags: #API#GraphQL
Share:

Comments

Sign in with your GitHub account to join the discussion. Comments are stored in GitHub Discussions.

Related Posts

Search the site

Start typing to search posts, projects and pages.

Esc to close Powered by Pagefind