İçindekiler
Modern uygulamalarda veriyi almak, çoğu zaman veriyi göstermekten daha karmaşık hâle gelir. Geleneksel REST API’lerde bir ekran için birden fazla uç noktaya istek atmak veya gereğinden büyük JSON yanıtları indirmek sık rastlanan bir durumdur. GraphQL, istemcinin ihtiyaç duyduğu alanları açıkça tarif ettiği bir sorgu dili ve API çalışma zamanı sunar. Böylece mobil uygulama, web arayüzü ve yönetim paneli aynı veri kaynağından farklı şekillerde beslenebilir. ``
REST’teki iki klasik problem
REST yaklaşımında /users/42 çağrısı kullanıcının çok sayıda alanını döndürebilir. Oysa profil kartında yalnızca ad ve avatar gerekli olabilir. Bu over-fetching yani fazla veri çekme problemidir. Tersine, kullanıcıyı, yazılarını ve her yazının yorum sayısını göstermek için ayrı ayrı uç noktalara gitmek gerekebilir. Bu da under-fetching olarak bilinir.
GraphQL’de istemci, sunucuya sadece sonuç biçimini bildirir. Sunucu ise şemada tanımlanan kurallara göre bu biçimi üretir. Veri maliyetini kabaca şöyle düşünebiliriz:
\[Maliyet \approx İstek\ Sayısı \times Gecikme + Aktarılan\ Veri\ Boyutu\]GraphQL her zaman bu maliyeti otomatik olarak en aza indirmez; ancak istemciye veri boyutunu ve ilişkisel sorguları hassas biçimde yönetme olanağı verir.
| Özellik | REST | GraphQL |
|---|---|---|
| Veri şekli | Sunucu belirler | İstemci alan seçer |
| Uç nokta | Genellikle çok sayıda | Çoğunlukla tek uç nokta |
| Dokümantasyon | Harici olabilir | Şema üzerinden keşfedilebilir |
| İlişkili veri | Birden çok çağrı gerekebilir | Tek sorguda istenebilir |
Şema: API’nin sözleşmesi
GraphQL sisteminin kalbinde schema bulunur. Şema; hangi nesnelerin, alanların ve işlemlerin kullanılabileceğini tanımlar. User türünün id, name ve posts alanlarına sahip olduğunu düşünelim. Query türü ise dışarıdan erişilebilen başlangıç noktalarını sunar.
type Post {
id: ID!
title: String!
likes: Int!
}
type User {
id: ID!
name: String!
avatarUrl: String
posts: [Post!]!
}
type Query {
user(id: ID!): User
}
Buradaki !, alanın boş olamayacağını belirtir. [Post!]! ifadesi hem listenin boş olmamasını hem de listedeki öğelerin null olmamasını garanti eder. Bu tip sistemi, istemcinin daha geliştirme aşamasında hatalı alan taleplerini yakalamasına yardımcı olur.
İstemci odaklı sorgu yazmak
Profil kartı için bütün kullanıcı kaydını istemek yerine, görünümün kullandığı alanları seçebiliriz:
query GetProfile($userId: ID!) {
user(id: $userId) {
name
avatarUrl
posts {
title
likes
}
}
}
Değişkenler ayrı gönderilir:
{ "userId": "42" }
Bu sorgu, SQL yazmak değildir. İstemci verinin nasıl bulunacağını değil, hangi biçimde dönmesini istediğini ifade eder. Arka planda alanları çözme görevini resolver’lar üstlenir. Örneğin user resolver’ı kullanıcıyı veritabanından bulur; posts resolver’ı ise o kullanıcının yazılarını getirir.
Dikkat: Tek sorgu, sınırsız maliyet demek değildir
GraphQL’in esnekliği kontrol edilmezse pahalı iç içe sorgulara dönüşebilir. Özellikle liste içindeki her öğe için yeniden veritabanı sorgusu çalıştırılması N+1 problemi yaratır. Bunu önlemek için DataLoader benzeri toplu yükleme araçları, sorgu derinliği limitleri ve karmaşıklık analizi kullanılır.
| İhtiyaç | Öneri |
|---|---|
| Tekil profil görünümü | Alanları açıkça seçen query |
| Kayıt oluşturma | mutation |
| Canlı bildirim | subscription |
| Büyük liste | Sayfalama ve first/after parametreleri |
Sonuç olarak GraphQL, “tek endpoint her derdi çözer” sloganından çok daha fazlasıdır: güçlü bir API sözleşmesidir. İyi tasarlanmış bir şema, sınırlandırılmış sorgu maliyetleri ve sayfalama kurallarıyla birleştiğinde, istemci ekiplerinin daha az gereksiz veri taşıyarak daha hızlı ve esnek arayüzler geliştirmesini sağlar.
Yorumlar