↑↓ seç · Enter aç · Esc kapat

Mutlu Tekin
Mutlu Tekin
← Yazılar

Bölüm 5 — Konu 20: HTTP İstekleri (`http` / `dio` Paketleri)

3 dk okuma #flutter
Dizi · 20/61 Flutter Türkçe Tutorial
  1. Bölüm 1 — Konu 1: Flutter Nedir, Mimarisi (Widget → Element → RenderObject, Skia/Impeller)
  2. Bölüm 1 — Konu 2: Ortam Kurulumu (Flutter SDK, Android Studio/VS Code, Emulator/Simulator, DevTools'a İlk Bakış)
  3. Bölüm 1 — Konu 3: İlk Proje Yapısı (`pubspec.yaml`, `lib/`, Klasör Mimarisi, `flutter create` Anatomisi)
  4. Bölüm 1 — Konu 4: Hot Reload / Hot Restart Ne Yapıyor, Neden Önemli
  5. Bölüm 2 — Konu 5: "Her Şey Widget'tır" Felsefesi, Widget Ağacı
  6. Bölüm 2 — Konu 6: StatelessWidget vs StatefulWidget + `setState()` Derinlemesine (Rebuild Mekanizması)
  7. Bölüm 2 — Konu 7: Temel Layout — Container, Row, Column, Stack, Padding, Align, Center
  8. Bölüm 2 — Konu 8: Constraint Sistemi — "Constraints Go Down, Sizes Go Up, Parent Sets Position"
  9. Bölüm 2 — Konu 9: `Expanded`, `Flexible`, `Spacer`, Intrinsic Widget'lar
  10. Bölüm 3 — Konu 10: MaterialApp/CupertinoApp, Scaffold, AppBar
  11. Bölüm 3 — Konu 11: `ListView`, `GridView`, `SingleChildScrollView` (+ Builder Pattern)
  12. Bölüm 3 — Konu 12: Text, TextStyle, Icon, Image, Asset Yönetimi
  13. Bölüm 3 — Konu 13: Custom Widget Yazma Prensipleri (Composition Over Inheritance)
  14. Bölüm 3 — Konu 14: Navigator 1.0 — Push/Pop, Named Routes
  15. Bölüm 4 — Konu 15: Form, TextField/TextFormField, GlobalKey<FormState>, Validasyon
  16. Bölüm 4 — Konu 16: Theme Sistemi (ThemeData, ColorScheme)
  17. Bölüm 4 — Konu 17: Responsive & Adaptive Tasarım (MediaQuery, LayoutBuilder, OrientationBuilder, Breakpoint Stratejileri)
  18. Bölüm 5 — Konu 18: Future/Async-Await Flutter Bağlamında, FutureBuilder
  19. Bölüm 5 — Konu 19: `Stream`, `StreamBuilder`
  20. Bölüm 5 — Konu 20: HTTP İstekleri (`http` / `dio` Paketleri)
  21. Bölüm 5 — Konu 21: JSON Serialization (Manuel → `json_serializable`/`freezed`)
  22. Bölüm 5 — Konu 22: Local Storage — `shared_preferences` → `Hive` → `sqflite`/Drift
  23. Bölüm 6 — Konu 23: InheritedWidget ve InheritedModel — "Neden setState Yetmiyor" Sorusunun Cevabı
  24. Bölüm 6 — Konu 24: Provider Paketi
  25. Bölüm 6 — Konu 25: Riverpod (Modern Yaklaşım, Provider'ın Halefi)
  26. Bölüm 6 — Konu 26: BLoC/Cubit Pattern (`flutter_bloc`)
  27. Bölüm 6 — Konu 27: GetX (Tartışmalı Ama Yaygın)
  28. Bölüm 6 — Konu 28: Karşılaştırma — Hangi Projede Hangisi?
  29. Bölüm 7 — Konu 29: Navigator 2.0 (Router, RouteInformationParser, RouterDelegate)
  30. Bölüm 7 — Konu 30: `go_router` Paketi (Pratik ve Modern Çözüm)
  31. Bölüm 7 — Konu 31: Deep Linking
  32. Bölüm 7 — Konu 32: Repository Pattern, Katmanlı Mimari (Data/Domain/Presentation)
  33. Bölüm 7 — Konu 33: Dependency Injection (`get_it`, `injectable`)
  34. Bölüm 7 — Konu 34: Clean Architecture Uyarlaması, SOLID Prensipleri
  35. Bölüm 8 — Konu 35: Implicit Animasyonlar
  36. Bölüm 8 — Konu 36: Explicit Animasyonlar (`AnimationController`, `Tween`, `Curve`)
  37. Bölüm 8 — Konu 37: Hero Animasyonları
  38. Bölüm 8 — Konu 38: `CustomPainter` / `Canvas`
  39. Bölüm 8 — Konu 39: Rive / Lottie Entegrasyonu
  40. Bölüm 9 — Konu 40: Platform Channels
  41. Bölüm 9 — Konu 41: Permission Yönetimi (`permission_handler`)
  42. Bölüm 9 — Konu 42: Kamera, Konum, Sensörler
  43. Bölüm 9 — Konu 43: Push Notification (Firebase Cloud Messaging)
  44. Bölüm 9 — Konu 44: Android/iOS Build Sistemleri
  45. Bölüm 10 — Konu 45: Test Yazımı (Unit, Widget, Integration, Golden)
  46. Bölüm 10 — Konu 46: CI/CD
  47. Bölüm 10 — Konu 47: Rebuild Optimizasyonu (`const`, `key` Kullanımı)
  48. Bölüm 10 — Konu 48: DevTools Profiling
  49. Bölüm 10 — Konu 49: Lazy Loading, Pagination, Büyük Liste Performansı
  50. Bölüm 11 — Konu 50: Firebase Ekosistemi (Auth, Firestore, Storage, Functions)
  51. Bölüm 11 — Konu 51: Supabase Alternatifi
  52. Bölüm 11 — Konu 52: GraphQL (Opsiyonel)
  53. Bölüm 11 — Konu 53: Store Yayınlama Süreci (İmzalama, Listing, Versiyonlama)
  54. Bölüm 11 — Konu 54: App Size, Obfuscation, Flavor Yönetimi
  55. Bölüm 12 — Konu 55: Flutter Web / Desktop
  56. Bölüm 12 — Konu 56: Custom `RenderObject` Yazımı
  57. Bölüm 12 — Konu 57: Engine Mimarisi Derinlemesine (Impeller vs Skia)
  58. Bölüm 12 — Konu 58: Plugin Geliştirme, pub.dev'e Paket Yayınlama
  59. Bölüm 12 — Konu 59: Monorepo Mimarisi (Melos)
  60. Bölüm 12 — Konu 60: Erişilebilirlik (Accessibility) Derinlemesine
  61. Bölüm 12 — Konu 61: Yerelleştirme (Localization / i18n)
Dizinin sayfası →
İçindekiler 9 başlık
  1. Paketi Ekleme — Dart Bölüm 12'yi Hatırlama
  2. Basit Bir GET İsteği
  3. JSON Parse Etme — dart:convert
  4. Bunu FutureBuilder ile Ekrana Bağlamak
  5. POST İsteği — Sunucuya Veri Gönderme
  6. dio Paketi — Daha Gelişmiş Bir Alternatif
  7. DioException — Dart Bölüm 8'i Hatırlama
  8. 🎯 Bu Dersten Çıkarılması Gerekenler
  9. 📝 Ödevler

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

bash
flutter pub add http

Bu, 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

dart
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

dart
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

dart
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

dart
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

bash
flutter pub add dio
dart
import '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

dart
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

  • http paketi, http.get()/http.post() ile basit HTTP istekleri yapmanı sağlar; Future<Response> döndürür.
  • jsonDecode(), JSON string'ini Map<String, dynamic>'e çevirir; jsonEncode() bunun tersini yapar.
  • FutureBuilder + initState()/late final kalıbı, gerçek API çağrılarında birebir aynı şekilde kullanılır.
  • dio paketi, 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

  • [ ] http paketi ile genel bir test API'sinden (jsonplaceholder.typicode.com gibi) veri çek, jsonDecode ile parse et, konsola yazdır.
  • [ ] Çektiğin veriyi, FutureBuilder + initState()/late final kalıbıyla bir ekranda göster.
  • [ ] http.post() ile aynı API'ye sahte bir veri gönder, cevabı yazdır.
  • [ ] dio paketini kur, aynı GET isteğini dio ile tekrar yap, otomatik JSON decode'un farkını gözlemle.
  • [ ] Var olmayan bir URL'ye istek atarak bir hata oluştur, FutureBuilder'ın snapshot.hasError mekanizması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)