Bölüm 5 — Konu 20: HTTP İstekleri (`http` / `dio` Paketleri)
Dizi · 20/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 9 başlık
Bu derste, uygulamanı gerçek bir API'ye bağlayacaksın — Bölüm 5 Konu 18'de simüle ettiğimiz "sahte gecikme"leri, artık gerçek ağ istekleriyle değiştireceğiz.
Paketi Ekleme — Dart Bölüm 12'yi Hatırlama
flutter pub add httpBu, Dart Bölüm 12 Konu 53'te öğrendiğimiz dart pub add'in birebir aynısı — Flutter projelerinde de aynı komut (flutter pub add, dart pub add'in Flutter'a özel bir sarmalayıcısıdır) kullanılır.
Basit Bir GET İsteği
import 'package:http/http.dart' as http;
import 'dart:convert';
Future<void> veriGetir() async {
final response = await http.get(
Uri.parse('https://jsonplaceholder.typicode.com/posts/1'),
);
if (response.statusCode == 200) {
print('Başarılı: ${response.body}');
} else {
print('Hata: ${response.statusCode}');
}
}import 'package:http/http.dart' as http; — Dart Bölüm 12 Konu 54'te öğrendiğimiz as ile isim çakışmasını önleme kalıbı burada standart bir pratik olarak kullanılıyor. http.get(...), Bölüm 5 Konu 18'de öğrendiğimiz Future<String> mantığına tamamen benzer bir Future<Response> döndürür — await ile bekliyoruz.
response.statusCode — HTTP protokolünün durum kodları (200 başarılı, 404 bulunamadı, 500 sunucu hatası gibi). Bu, Dart Bölüm 3'te öğrendiğimiz switch/if-else ile kontrol edilebilecek bir değerdir.
JSON Parse Etme — dart:convert
import 'dart:convert';
Future<void> veriGetir() async {
final response = await http.get(Uri.parse('https://jsonplaceholder.typicode.com/posts/1'));
if (response.statusCode == 200) {
final Map<String, dynamic> veri = jsonDecode(response.body);
print(veri['title']); // JSON içindeki 'title' alanına erişim
}
}jsonDecode(), bir JSON string'ini, Dart Bölüm 4'te öğrendiğimiz Map<String, dynamic> (veya List<dynamic>, eğer JSON bir dizi ise) yapısına çevirir. Bölüm 4 Konu 18'de "JSON gibi karışık tipli verilerle çalışırken dynamic meşru bir kullanım alanıdır" demiştik — işte tam olarak bu senaryo.
Bunu FutureBuilder ile Ekrana Bağlamak
class GonderiEkrani extends StatefulWidget {
const GonderiEkrani({super.key});
@override
State<GonderiEkrani> createState() => _GonderiEkraniState();
}
class _GonderiEkraniState extends State<GonderiEkrani> {
late final Future<Map<String, dynamic>> _gonderiFuture; // Bölüm 5 Konu 18'deki kalıp!
@override
void initState() {
super.initState();
_gonderiFuture = _gonderiGetir();
}
Future<Map<String, dynamic>> _gonderiGetir() async {
final response = await http.get(
Uri.parse('https://jsonplaceholder.typicode.com/posts/1'),
);
if (response.statusCode == 200) {
return jsonDecode(response.body);
} else {
throw Exception('Veri alınamadı: ${response.statusCode}'); // Dart Bölüm 8'i hatırla
}
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: Text('Gönderi')),
body: FutureBuilder<Map<String, dynamic>>(
future: _gonderiFuture,
builder: (context, snapshot) {
if (snapshot.connectionState == ConnectionState.waiting) {
return Center(child: CircularProgressIndicator());
}
if (snapshot.hasError) {
return Center(child: Text('Hata: ${snapshot.error}'));
}
final veri = snapshot.data!;
return Padding(
padding: EdgeInsets.all(16),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(veri['title'], style: TextStyle(fontSize: 20, fontWeight: FontWeight.bold)),
SizedBox(height: 8),
Text(veri['body']),
],
),
);
},
),
);
}
}Bu kod, Bölüm 5 Konu 18'de öğrendiğimiz tüm doğru pratiği (late final + initState()) gerçek bir API çağrısıyla birleştiriyor — ve Dart Bölüm 8'de öğrendiğimiz throw Exception(...)'ın, FutureBuilder'ın snapshot.hasError mekanizmasıyla doğal olarak nasıl entegre olduğunu gösteriyor.
POST İsteği — Sunucuya Veri Gönderme
Future<void> gonderiOlustur(String baslik, String icerik) async {
final response = await http.post(
Uri.parse('https://jsonplaceholder.typicode.com/posts'),
headers: {'Content-Type': 'application/json'},
body: jsonEncode({
'title': baslik,
'body': icerik,
}),
);
if (response.statusCode == 201) {
print('Gönderi oluşturuldu: ${response.body}');
}
}jsonEncode(), jsonDecode()'un tersidir — bir Dart Map (veya List) alır, JSON string'ine çevirir. Dart Bölüm 4'te öğrendiğimiz {...} map literal sözdizimini kullanarak, sunucuya göndereceğin veriyi kolayca oluşturabiliyorsun.
dio Paketi — Daha Gelişmiş Bir Alternatif
flutter pub add dioimport 'package:dio/dio.dart';
final dio = Dio();
Future<void> veriGetir() async {
try {
final response = await dio.get('https://jsonplaceholder.typicode.com/posts/1');
print(response.data); // dio, JSON'u OTOMATİK olarak decode eder!
} on DioException catch (e) {
print('Hata: ${e.message}');
}
}http ile dio arasındaki temel farklar:
| Özellik | http |
dio |
|---|---|---|
| JSON otomatik decode | ❌ Elle jsonDecode() gerekir |
✅ Otomatik |
| İstek/cevap interceptor'ları | ❌ Yok | ✅ Var (her isteğe otomatik token ekleme gibi) |
| İptal edilebilir istekler | ⚠️ Sınırlı | ✅ Gelişmiş (CancelToken) |
| Dosya yükleme (multipart) | ⚠️ Elle kurulmalı | ✅ Kolay API |
| Öğrenme eğrisi | Düşük, basit | Biraz daha fazla kavram |
Pratik tavsiye: Basit, küçük projeler için http yeterlidir. Daha büyük uygulamalarda, özellikle her isteğe otomatik bir authentication token eklemek, istekleri loglama, veya karmaşık hata yönetimi gerektiğinde, dio'nun sunduğu interceptor mekanizması çok değerli hale gelir.
DioException — Dart Bölüm 8'i Hatırlama
try {
final response = await dio.get('https://olmayan-bir-site.com');
} on DioException catch (e) {
if (e.type == DioExceptionType.connectionTimeout) {
print('Bağlantı zaman aşımına uğradı');
} else if (e.type == DioExceptionType.badResponse) {
print('Sunucu hatası: ${e.response?.statusCode}');
} else {
print('Bilinmeyen hata: ${e.message}');
}
}Bu, Dart Bölüm 8 Konu 39'da öğrendiğimiz özel exception sınıfları ve on TipAdı catch kalıbının, dio paketinin kendi tanımladığı bir exception türü (DioException) ile kullanılmasıdır — üçüncü parti paketler, kendi özel exception hiyerarşilerini tanımlayarak, sana daha anlamlı hata yönetimi imkanı sunar.
🎯 Bu Dersten Çıkarılması Gerekenler
httppaketi,http.get()/http.post()ile basit HTTP istekleri yapmanı sağlar;Future<Response>döndürür.jsonDecode(), JSON string'iniMap<String, dynamic>'e çevirir;jsonEncode()bunun tersini yapar.FutureBuilder+initState()/late finalkalıbı, gerçek API çağrılarında birebir aynı şekilde kullanılır.diopaketi, otomatik JSON decode, interceptor'lar ve gelişmiş hata yönetimi sunan daha güçlü bir alternatiftir.DioException, Dart'ta öğrendiğimiz özel exception sınıflarının, üçüncü parti bir pakette nasıl kullanıldığına dair gerçek bir örnektir.
📝 Ödevler
- [ ]
httppaketi ile genel bir test API'sinden (jsonplaceholder.typicode.com gibi) veri çek,jsonDecodeile parse et, konsola yazdır. - [ ] Çektiğin veriyi,
FutureBuilder+initState()/late finalkalıbıyla bir ekranda göster. - [ ]
http.post()ile aynı API'ye sahte bir veri gönder, cevabı yazdır. - [ ]
diopaketini kur, aynı GET isteğinidioile tekrar yap, otomatik JSON decode'un farkını gözlemle. - [ ] Var olmayan bir URL'ye istek atarak bir hata oluştur,
FutureBuilder'ınsnapshot.hasErrormekanizmasıyla kullanıcıya anlamlı bir hata mesajı göster.
Sıradaki konu: Bölüm 5 — Konu 21: JSON Serialization (Manuel → json_serializable/freezed)