Bölüm 11 — Konu 52: GraphQL (Opsiyonel)
Dizi · 52/61 Flutter Türkçe Tutorial
- Bölüm 1 — Konu 1: Flutter Nedir, Mimarisi (Widget → Element → RenderObject, Skia/Impeller)
- Bölüm 1 — Konu 2: Ortam Kurulumu (Flutter SDK, Android Studio/VS Code, Emulator/Simulator, DevTools'a İlk Bakış)
- Bölüm 1 — Konu 3: İlk Proje Yapısı (`pubspec.yaml`, `lib/`, Klasör Mimarisi, `flutter create` Anatomisi)
- Bölüm 1 — Konu 4: Hot Reload / Hot Restart Ne Yapıyor, Neden Önemli
- Bölüm 2 — Konu 5: "Her Şey Widget'tır" Felsefesi, Widget Ağacı
- Bölüm 2 — Konu 6: StatelessWidget vs StatefulWidget + `setState()` Derinlemesine (Rebuild Mekanizması)
- Bölüm 2 — Konu 7: Temel Layout — Container, Row, Column, Stack, Padding, Align, Center
- Bölüm 2 — Konu 8: Constraint Sistemi — "Constraints Go Down, Sizes Go Up, Parent Sets Position"
- Bölüm 2 — Konu 9: `Expanded`, `Flexible`, `Spacer`, Intrinsic Widget'lar
- Bölüm 3 — Konu 10: MaterialApp/CupertinoApp, Scaffold, AppBar
- Bölüm 3 — Konu 11: `ListView`, `GridView`, `SingleChildScrollView` (+ Builder Pattern)
- Bölüm 3 — Konu 12: Text, TextStyle, Icon, Image, Asset Yönetimi
- Bölüm 3 — Konu 13: Custom Widget Yazma Prensipleri (Composition Over Inheritance)
- Bölüm 3 — Konu 14: Navigator 1.0 — Push/Pop, Named Routes
- Bölüm 4 — Konu 15: Form, TextField/TextFormField, GlobalKey<FormState>, Validasyon
- Bölüm 4 — Konu 16: Theme Sistemi (ThemeData, ColorScheme)
- Bölüm 4 — Konu 17: Responsive & Adaptive Tasarım (MediaQuery, LayoutBuilder, OrientationBuilder, Breakpoint Stratejileri)
- Bölüm 5 — Konu 18: Future/Async-Await Flutter Bağlamında, FutureBuilder
- Bölüm 5 — Konu 19: `Stream`, `StreamBuilder`
- Bölüm 5 — Konu 20: HTTP İstekleri (`http` / `dio` Paketleri)
- Bölüm 5 — Konu 21: JSON Serialization (Manuel → `json_serializable`/`freezed`)
- Bölüm 5 — Konu 22: Local Storage — `shared_preferences` → `Hive` → `sqflite`/Drift
- Bölüm 6 — Konu 23: InheritedWidget ve InheritedModel — "Neden setState Yetmiyor" Sorusunun Cevabı
- Bölüm 6 — Konu 24: Provider Paketi
- Bölüm 6 — Konu 25: Riverpod (Modern Yaklaşım, Provider'ın Halefi)
- Bölüm 6 — Konu 26: BLoC/Cubit Pattern (`flutter_bloc`)
- Bölüm 6 — Konu 27: GetX (Tartışmalı Ama Yaygın)
- Bölüm 6 — Konu 28: Karşılaştırma — Hangi Projede Hangisi?
- Bölüm 7 — Konu 29: Navigator 2.0 (Router, RouteInformationParser, RouterDelegate)
- Bölüm 7 — Konu 30: `go_router` Paketi (Pratik ve Modern Çözüm)
- Bölüm 7 — Konu 31: Deep Linking
- Bölüm 7 — Konu 32: Repository Pattern, Katmanlı Mimari (Data/Domain/Presentation)
- Bölüm 7 — Konu 33: Dependency Injection (`get_it`, `injectable`)
- Bölüm 7 — Konu 34: Clean Architecture Uyarlaması, SOLID Prensipleri
- Bölüm 8 — Konu 35: Implicit Animasyonlar
- Bölüm 8 — Konu 36: Explicit Animasyonlar (`AnimationController`, `Tween`, `Curve`)
- Bölüm 8 — Konu 37: Hero Animasyonları
- Bölüm 8 — Konu 38: `CustomPainter` / `Canvas`
- Bölüm 8 — Konu 39: Rive / Lottie Entegrasyonu
- Bölüm 9 — Konu 40: Platform Channels
- Bölüm 9 — Konu 41: Permission Yönetimi (`permission_handler`)
- Bölüm 9 — Konu 42: Kamera, Konum, Sensörler
- Bölüm 9 — Konu 43: Push Notification (Firebase Cloud Messaging)
- Bölüm 9 — Konu 44: Android/iOS Build Sistemleri
- Bölüm 10 — Konu 45: Test Yazımı (Unit, Widget, Integration, Golden)
- Bölüm 10 — Konu 46: CI/CD
- Bölüm 10 — Konu 47: Rebuild Optimizasyonu (`const`, `key` Kullanımı)
- Bölüm 10 — Konu 48: DevTools Profiling
- Bölüm 10 — Konu 49: Lazy Loading, Pagination, Büyük Liste Performansı
- Bölüm 11 — Konu 50: Firebase Ekosistemi (Auth, Firestore, Storage, Functions)
- Bölüm 11 — Konu 51: Supabase Alternatifi
- Bölüm 11 — Konu 52: GraphQL (Opsiyonel)
- Bölüm 11 — Konu 53: Store Yayınlama Süreci (İmzalama, Listing, Versiyonlama)
- Bölüm 11 — Konu 54: App Size, Obfuscation, Flavor Yönetimi
- Bölüm 12 — Konu 55: Flutter Web / Desktop
- Bölüm 12 — Konu 56: Custom `RenderObject` Yazımı
- Bölüm 12 — Konu 57: Engine Mimarisi Derinlemesine (Impeller vs Skia)
- Bölüm 12 — Konu 58: Plugin Geliştirme, pub.dev'e Paket Yayınlama
- Bölüm 12 — Konu 59: Monorepo Mimarisi (Melos)
- Bölüm 12 — Konu 60: Erişilebilirlik (Accessibility) Derinlemesine
- Bölüm 12 — Konu 61: Yerelleştirme (Localization / i18n)
İçindekiler 11 başlık
- REST'in Sorunu — Over-fetching ve Under-fetching
- GraphQL'in Çözümü — "Ne İstediğini Sen Söyle"
- Şema ve Tip Sistemi — Dart'ın Statik Tiplemesine Benzer Bir Güvence
- Flutter'da Kullanım — graphql_flutter
- Query — Veri Okuma
- Mutation — Veri Değiştirme
- Subscription — Gerçek Zamanlı Veri
- GraphQL vs REST vs Firestore/Supabase — Nerede Durur?
- Pratik Gerçek — Ne Zaman Karşına Çıkar?
- 🎯 Bu Dersten Çıkarılması Gerekenler
- 📝 Ödevler (Opsiyonel)
Bu konu opsiyonel işaretli — GraphQL, her projede karşına çıkmaz, ama özellikle büyük/kurumsal API'lerde (GitHub API, Shopify, birçok modern SaaS ürünü) giderek yaygınlaşan bir alternatif. Temel fikri anlaman, bir gün "bu API GraphQL kullanıyor" ile karşılaştığında şaşırmaman için yeterli.
REST'in Sorunu — Over-fetching ve Under-fetching
Bölüm 5 Konu 20'de öğrendiğimiz REST API'leri hatırla — her endpoint, sabit bir yapıda veri döner:
GET /kullanicilar/123
→ { id, isim, eposta, adres, telefon, kayitTarihi, ... TÜM ALANLAR }Diyelim ki arayüzünde sadece kullanıcının ismini göstermen gerekiyor — REST, yine de tüm alanları gönderir (over-fetching — ihtiyacından fazlasını çekme). Ya da tam tersi: kullanıcının hem bilgilerini hem son 5 siparişini göstermen gerekiyorsa, iki ayrı istek atman gerekebilir (under-fetching — bir istekte yetmemesi).
GraphQL'in Çözümü — "Ne İstediğini Sen Söyle"
query {
kullanici(id: "123") {
isim
siparisler(limit: 5) {
urunAdi
fiyat
}
}
}GraphQL'de, istemci (senin Flutter uygulaman), tam olarak hangi alanları istediğini sorgunun içinde belirtir — sunucu, sadece istenen alanları, tek bir istekte döner. Bu, Bölüm 11 Konu 51'de Supabase'in .select('isim') ile "sadece bu sütunu getir" demesine kavramsal olarak benziyor — ama GraphQL bunu iç içe geçmiş ilişkiler için de (yukarıdaki örnekte olduğu gibi, kullanıcı + siparişleri tek seferde) doğal olarak destekler.
Şema ve Tip Sistemi — Dart'ın Statik Tiplemesine Benzer Bir Güvence
type Kullanici {
id: ID!
isim: String!
eposta: String!
siparisler: [Siparis!]!
}GraphQL API'leri, Dart Bölüm 1-2'de öğrendiğimiz statik tip sistemine benzer bir şema ile tanımlanır — ! işareti, Dart'ın non-nullable (String vs String?) mantığına birebir karşılık gelir ("bu alan asla null olamaz" demektir). Bu şema sayesinde, bir GraphQL sorgusu derleme zamanında bile (uygun araçlarla) doğrulanabilir — "böyle bir alan yok" hatası, API'ye istek atmadan önce yakalanabilir.
Flutter'da Kullanım — graphql_flutter
flutter pub add graphql_flutterfinal HttpLink httpLink = HttpLink('https://api.ornek.com/graphql');
final ValueNotifier<GraphQLClient> client = ValueNotifier(
GraphQLClient(link: httpLink, cache: GraphQLCache()),
);Query — Veri Okuma
const String kullaniciSorgusu = r'''
query KullaniciGetir($id: ID!) {
kullanici(id: $id) {
isim
eposta
}
}
''';
Query(
options: QueryOptions(
document: gql(kullaniciSorgusu),
variables: {'id': '123'},
),
builder: (QueryResult sonuc, {refetch, fetchMore}) {
if (sonuc.isLoading) return const CircularProgressIndicator();
if (sonuc.hasException) return Text('Hata: ${sonuc.exception}');
final kullanici = sonuc.data!['kullanici'];
return Text(kullanici['isim']);
},
)Query widget'ı, Bölüm 5 Konu 18'de öğrendiğimiz FutureBuilder'a kavramsal olarak çok benziyor — isLoading/hasException/data durumlarını, Flutter'ın builder pattern'i (Bölüm 3 Konu 11) ile tutarlı bir şekilde yönetiyor. $id: ID! gibi değişkenler, Dart Bölüm 6'da öğrendiğimiz parametreli fonksiyon çağrısına benzer bir mantıkla, sorguyu yeniden kullanılabilir yapıyor (variables: {'id': '123'} ile "doldurulur").
Mutation — Veri Değiştirme
const String kullaniciGuncelle = r'''
mutation KullaniciGuncelle($id: ID!, $isim: String!) {
kullaniciGuncelle(id: $id, isim: $isim) {
id
isim
}
}
''';
Mutation(
options: MutationOptions(document: gql(kullaniciGuncelle)),
builder: (RunMutation calistir, QueryResult? sonuc) {
return ElevatedButton(
onPressed: () => calistir({'id': '123', 'isim': 'Yeni İsim'}),
child: const Text('Güncelle'),
);
},
)GraphQL'de okuma işlemleri query, yazma/değiştirme işlemleri mutation olarak adlandırılır — bu, REST'teki GET (okuma) ile POST/PUT/DELETE (değiştirme) ayrımının GraphQL karşılığıdır.
Subscription — Gerçek Zamanlı Veri
const String yeniMesajAkisi = r'''
subscription {
yeniMesaj {
gonderen
icerik
}
}
''';
Subscription(
options: SubscriptionOptions(document: gql(yeniMesajAkisi)),
builder: (QueryResult sonuc) {
if (!sonuc.hasException && sonuc.data != null) {
return Text(sonuc.data!['yeniMesaj']['icerik']);
}
return const Text('Mesaj bekleniyor...');
},
)subscription, Bölüm 11 Konu 50-51'de Firestore'un .snapshots()'ı ve Supabase'in .stream()'i ile aynı fikri — sunucudan sürekli akan veri — GraphQL dünyasında ifade eder. Altyapıda genelde WebSocket kullanılır (Bölüm 5 Konu 19'da öğrendiğimiz Stream kavramının, ağ üzerinden sürekli açık bir bağlantı ile taşınan hali).
GraphQL vs REST vs Firestore/Supabase — Nerede Durur?
| REST | GraphQL | Firestore/Supabase | |
|---|---|---|---|
| İstek başına veri kontrolü | Sabit (sunucu belirler) | İstemci belirler (esnek) | Sorgu ile kısmen belirlenir |
| Birden fazla kaynak, tek istek | Genelde hayır | Evet (iç içe sorgular) | Supabase'de join ile kısmen |
| Öğrenme eğrisi | Düşük | Orta (şema, sorgu dili) | Düşük-orta |
| Gerçek zamanlı destek | Yok (elle WebSocket kurulur) | subscription ile yerleşik |
.snapshots()/.stream() ile yerleşik |
| En uygun olduğu senaryo | Basit, öngörülebilir API'ler | Karmaşık, iç içe veri ihtiyaçları olan büyük uygulamalar | Kendi backend'ini Firebase/Supabase'e emanet eden projeler |
Pratik Gerçek — Ne Zaman Karşına Çıkar?
Kendi backend'ini (Bölüm 11 Konu 50-51'deki Firebase/Supabase ya da kendi yazdığın bir sunucu) sen tasarlıyorsan, GraphQL'i baştan seçmen nadiren gerekir — REST (Bölüm 5 Konu 20) ya da Firestore/Supabase'in kendi sorgu API'leri genelde yeterlidir. GraphQL'in asıl değeri, büyük, birden fazla ekibin aynı API'yi farklı ihtiyaçlarla kullandığı kurumsal ortamlarda ortaya çıkar — ya da hazır bir GraphQL API'sine (örneğin bir üçüncü parti servis) client olarak bağlanman gerektiğinde.
🎯 Bu Dersten Çıkarılması Gerekenler
- GraphQL, REST'in over-fetching/under-fetching sorununu, istemcinin tam olarak hangi alanları istediğini sorgunun içinde belirtmesine izin vererek çözer.
- Şema ve tip sistemi (
!ile non-nullable), Dart'ın statik tiplemesine benzer bir güvence sağlar. query(okuma),mutation(yazma),subscription(gerçek zamanlı akış) — REST'teki HTTP metodlarının ve Firestore/Supabase'in stream API'lerinin GraphQL karşılıkları.graphql_flutter'dakiQuery/Mutationwidget'ları,FutureBuilder'a kavramsal olarak çok benzer bir builder pattern kullanır.- Pratikte, kendi backend'ini tasarlarken GraphQL zorunlu değildir — büyük/kurumsal API'lerde ya da hazır bir GraphQL servisine bağlanırken karşına çıkar.
📝 Ödevler (Opsiyonel)
- [ ] Herkese açık bir GraphQL API'sini (örn. countries.trevorblades.com)
graphql_flutterile sorgula, sonucu bir listede göster. - [ ] Aynı veriyi REST ile çekmiş olsaydın kaç istek gerekeceğini, GraphQL'in tek istekte nasıl çözdüğünü karşılaştırarak kendi cümlelerinle yaz.
- [ ] Bir GraphQL şemasındaki
!işaretlerinin, Dart'ın nullable/non-nullable (StringvsString?) sistemiyle nasıl paralel olduğunu açıkla.
Sıradaki konu: Bölüm 11 — Konu 53: Store Yayınlama Süreci (İmzalama, Listing, Versiyonlama)