REST vs GraphQL: Hangisini, Ne Zaman Seçmeli?

Blog · 17 Jun 2024

REST vs GraphQL: Hangisini, Ne Zaman Seçmeli?

Bir API tasarlarken karşına çıkan ilk büyük kararlardan biri: REST mi, GraphQL mi? İkisi de "frontend ile backend nasıl konuşacak" sorusuna cevap veriyor ama yaklaşımları temelden farklı. Bu yazıda ikisini teorik tanımların ötesinde, gerçek örneklerle ve "ne zaman hangisi" sorusuna net cevaplarla karşılaştıracağım.

Hemen söyleyeyim: bu bir "X öldü, Y kazandı" yazısı değil. İkisinin de yeri var, ve doğru kararı projenin ihtiyacı belirliyor.

Önce kısa bir hatırlatma

REST, kaynakları (resource) URL'ler üzerinden temsil eden bir mimari yaklaşım. Her kaynağın kendi endpoint'i var ve HTTP metodlarıyla (GET, POST, PUT, DELETE) bu kaynaklar üzerinde işlem yapıyorsun.

restGET    /users/42
GET    /users/42/posts
POST   /posts
DELETE /posts/17

GraphQL, Facebook'un geliştirdiği bir sorgu dili. Tek bir endpoint'in var (/graphql) ve istemci tam olarak hangi veriyi istediğini sorgu içinde belirtiyor. Sunucu da sadece istenen veriyi döndürüyor.

graphqlquery {
  user(id: 42) {
    name
    posts {
      title
    }
  }
}

Asıl fark: veriyi kim şekillendiriyor?

İki yaklaşım arasındaki en kritik fark bence bu. REST'te veriyi sunucu şekillendirir. Endpoint'i tasarlayan kişi, o endpoint'in ne döneceğine karar verir. GraphQL'de ise veriyi istemci şekillendirir. Frontend, ihtiyacı olanı tam olarak ister.

Bu fark, günlük geliştirmede üç somut soruna dokunuyor.

Over-fetching ve under-fetching

REST'te bir kullanıcının sadece adını isteyeceğin bir ekran için /users/42 çağırdığında, muhtemelen e-posta, kayıt tarihi, profil fotoğrafı, adres... hepsini birden alırsın. İhtiyacından fazlasını çekersin — buna over-fetching denir.

Tersi de var. Bir kullanıcıyı ve onun son 5 yazısını göstermek istiyorsun. REST'te genelde iki istek atarsın:

restGET /users/42
GET /users/42/posts?limit=5

Tek istekte istediğin her şeyi alamazsın — buna under-fetching denir ve sonucu "N+1 istek" problemidir.

GraphQL bu iki sorunu da kökünden çözer. Tek sorguda, tam istediğin alanları, iç içe ilişkilerle birlikte alırsın:

graphqlquery {
  user(id: 42) {
    name
    posts(last: 5) {
      title
      createdAt
    }
  }
}

Tek istek, sıfır fazlalık. Özellikle mobil uygulamalarda, her byte ve her round-trip önemliyken bu büyük bir avantaj.

Versiyonlama

REST API'lerde alan ekleyip çıkardıkça versiyonlama derdi başlar: /v1/users, /v2/users... Eski istemcileri kırmamak için eski versiyonları yaşatmak gerekir.

GraphQL'de genelde versiyonlama yapmazsın. Yeni alan eklemek mevcut sorguları kırmaz; eski alanları da @deprecated ile işaretleyip zamanla emekliye ayırırsın. Schema sürekli evrilir ama tek kalır.

Tip güvenliği ve dokümantasyon

GraphQL'in en sevdiğim yanlarından biri: schema'nın kendisi bir sözleşme. Her alanın tipi belli, ve bu sayede otomatik dokümantasyon, otomatik tip üretimi (TypeScript ile harika çalışır) ve GraphiQL gibi interaktif keşif araçları "bedava" gelir. REST'te aynı seviyeye ulaşmak için OpenAPI/Swagger gibi ek katmanlar kurman gerekir.

Peki REST'in üstünlüğü nerede?

GraphQL'i bu kadar övdükten sonra dengeyi kuralım, çünkü REST hâlâ çoğu durumda doğru tercih.

Caching. Bu, REST'in en güçlü kozu. REST, HTTP'nin doğal caching mekanizmasıyla mükemmel uyumlu. GET /users/42 isteğini tarayıcı, CDN, ara katman... her yer cache'leyebilir. GraphQL'de her şey POST ile tek endpoint'e gittiği için bu otomatik caching çalışmaz; cache'i uygulama seviyesinde (Apollo Client gibi) kendin yönetmen gerekir.

Basitlik. REST'i herkes biliyor. Yeni bir geliştirici ekibe katıldığında GET /products ne yapar diye düşünmesi gerekmez. GraphQL'in öğrenme eğrisi daha dik: resolver'lar, schema tasarımı, N+1 problemine karşı DataLoader gibi konular...

Dosya yükleme, basit CRUD. İşin çoğu standart "oluştur-oku-güncelle-sil" ise GraphQL fazladan karmaşıklık getirir. REST burada daha doğrudan.

İzleme ve hız limiti (rate limiting). REST'te endpoint bazında metrik toplamak, log tutmak, rate limit koymak kolaydır. GraphQL'de her sorgu tek endpoint'e gittiği ve karmaşıklığı değişken olduğu için bunlar daha zahmetlidir — bir kullanıcı tek sorguda devasa, iç içe bir istek atabilir.

Aynı işi iki yaklaşımla yan yana

Diyelim bir blog ana sayfası yapıyorsun: yazar bilgisi + son 3 yazısı + her yazının yorum sayısı.

REST ile (genelde birden fazla istek):

javascriptconst user = await fetch('/api/users/42').then(r => r.json());
const posts = await fetch('/api/users/42/posts?limit=3').then(r => r.json());
const comments = await Promise.all(
  posts.map(p => fetch(`/api/posts/${p.id}/comments/count`).then(r => r.json()))
);

Üç (hatta daha fazla) round-trip, frontend'de birleştirme işi sana kalıyor.

GraphQL ile (tek istek):

javascriptconst { data } = await fetch('/graphql', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    query: `
      query {
        user(id: 42) {
          name
          posts(last: 3) {
            title
            commentCount
          }
        }
      }
    `
  })
}).then(r => r.json());

Tek istek, veri zaten istediğin şekilde geliyor. Bu örnek GraphQL'in parladığı klasik senaryo: ilişkili, iç içe veriyi tek seferde toplama.

Karar tablosu

DurumÖnerim
Basit CRUD, az ilişkili veriREST
HTTP caching kritikREST
Public API (üçüncü partiler kullanacak)REST (daha tanıdık)
Karmaşık, iç içe, ilişkili veriGraphQL
Çok farklı istemci (web + mobil + IoT) aynı API’yi kullanıyorGraphQL
Frontend ekibi backend’e sürekli “şu alanı da ekler misin” diyorsaGraphQL
Küçük ekip, hız öncelik, ekstra altyapı istemiyorsunREST

Sonuç

Benim pratik kuralım şu: şüphedeysen REST'le başla. Çoğu proje için yeterli, herkes biliyor, altyapısı hazır. GraphQL'e geçişi, gerçek bir acı hissettiğinde yap — frontend ekibi sürekli over-fetching'den şikayet ediyorsa, tek ekran için 5 ayrı istek atıyorsan, ya da çok çeşitli istemcilere çok çeşitli veri şekilleri sunman gerekiyorsa.

İkisi birbirinin düşmanı da değil. Birçok ekip ikisini birlikte kullanıyor: dış dünyaya açık, cache'lenebilir uçlar için REST; karmaşık iç ekranlar için GraphQL. Doğru cevap "hangisi daha havalı" değil, "bu projenin gerçek derdi ne" sorusunda.

Senin projende hangisini kullanıyorsun, neden? Yorumlarda merak ediyorum.

← Tüm yazılar