İçeriğe geç
Muhammet Şafak
Web Geliştirme 3 dk okuma

REST'ten sonra: GraphQL'i denemek

Gerçek bir over-fetching sorununu GraphQL ile çözerken REST'in nerede yeterli, GraphQL'in nerede anlam kazandığını tartıyorum.


GraphQL yıllardır ilgimi çekiyordu ama “zaten REST çalışıyor” hissiyle erteledim. Bu yılın ortasında bir projede somut bir sorunla karşılaştım ve o sorunu çözmek için GraphQL’i gerçekten denemek gerekti. Şimdi hem ne bulduğumu hem de hangi durumlarda REST’in daha iyi kaldığını yazıyorum.

Somut sorun: bir mobil ekranı için çok fazla istek

Bir uygulama ekranı şunları gösteriyordu: kullanıcı profili, son üç siparişi ve her siparişteki ürün adları. REST ile bunun için üç ayrı uç nokta çağrısı yapıyorduk:

  1. GET /api/user/42 → profil
  2. GET /api/users/42/orders?limit=3 → siparişler
  3. Siparişlerin her biri için GET /api/orders/{id}/items (en az üç istek)

Toplam beş ila altı HTTP isteği. Her biri yanıt bekliyor, her birinde JSON ayrıştırması var. Ağ gecikmesi ekranın açılışını yavaşlatıyordu.

Öte yandan her endpoint fazladan veri de getiriyordu. Sipariş listesinde sipariş tarihi, ödeme yöntemi, adres bilgisi — ekranda hiçbiri görünmüyor. Bu fazla veriyi almak, aktarmak, ayrıştırmak zorundayız.

REST’te bu sorunların standart çözümleri var: include parametresiyle eager loading, özel endpoint’ler, API Gateway aggregation… Ama bunların hepsi sunucu tarafına yük bindiriyor ve her yeni ekran gereksinimi için yeni bir endpoint veya yeni bir parametre düzeneği gerektiriyor.

GraphQL nedir

GraphQL (Graph Query Language), Facebook’un geliştirdiği ve 2015’te açık kaynak yaptığı bir API sorgu dilidir. REST gibi bir protokol değil; istemcinin tam olarak ne istediğini belirttiği bir sorgu mekanizması.

Tek bir endpoint (/graphql), istemcinin gönderdiği sorguya göre farklı veriler döner:

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

Bu tek sorgu beş-altı REST isteğinin karşıladığı veriyi tek seferde getiriyor. İstemci tam olarak hangi alanları istediğini belirtiyor; sunucu yalnızca o alanları döndürüyor.

PHP’de Laravel ile GraphQL kurulumu

rebing/graphql-laravel paketi Laravel’de GraphQL sunucusu kurmayı nispeten kolaylaştırıyor:

composer require rebing/graphql-laravel

Tip tanımı:

<?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())],
        ];
    }
}

Sorgu tanımı:

<?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']);
    }
}

N+1 sorunu: GraphQL’in klasik tuzağı

GraphQL kullanmaya başlayınca N+1 sorunu hemen yüzüne çarpıyor. Bir kullanıcının siparişlerini, her siparişin ürünlerini istediğinizde resolver her sipariş için ayrı bir veritabanı sorgusu açabilir.

PHP ekosisteminde bu sorun için dataloader kütüphaneleri var. luckydonald/php-odata-query ya da overblog/dataloader-php gibi araçlar isteği batch’liyor. REST’te with() ile çözdüğünüz şeyi GraphQL’de daha dikkatli yönetmeniz gerekiyor.

Dürüst karşılaştırma

GraphQL’in mantıklı olduğu durumlar:

  • Birden fazla istemci (web, mobil, üçüncü parti) aynı API’yi kullanıyorsa ve her biri farklı veri ihtiyacı duyuyorsa.
  • Over-fetching ve under-fetching gerçek bir performans sorunu yaratıyorsa.
  • Hızla değişen UI gereksinimleri için backend değişikliği olmadan yeni sorgular açmak istiyorsanız.

REST’in daha iyi kaldığı durumlar:

  • Tek bir istemci var ve veri gereksinimleri nispeten öngörülebilir.
  • Basit CRUD işlemleri ağırlıklı.
  • Caching kritikse: REST endpoint’leri HTTP cache ile kolay önbelleklenebilir, GraphQL POST istekleri için bu daha zahmetli.
  • Ekip GraphQL araç zincirine yatırım yapacak olgunlukta değilse.

Bu deneyin sonunda GraphQL’i her yerde kullanmak yerine over-fetching gerçekten sorun olan kısımlarda tercih etmeye karar verdim. REST ve GraphQL aynı serviste bir arada da yaşayabiliyor.

Etiketler: #API#GraphQL
Paylaş:

İlgili Yazılar

Sitede Ara

Yazı, proje ve sayfalarda arama yapmak için yazmaya başlayın.

Esc ile kapat Pagefind ile güçlendirildi