اتصال فلاتر به سرور با Dio: مدل‌ها، خطاها و ساختار تمیز

هر اپ واقعی با یک API حرف می‌زند. این راهنما نشان می‌دهد چطور با Dio درخواست بزنید، پاسخ‌ها را به مدل Dart تبدیل کنید، خطاها را درست مدیریت کنید و کد شبکه را در یک لایه‌ی تمیز نگه دارید.

۳ دقیقه مطالعه
اتصال فلاتر به سرور با Dio: مدل‌ها، خطاها و ساختار تمیز

تقریباً هر اپ واقعی با یک سرور حرف می‌زند. فلاتر با پکیج http هم می‌تواند درخواست بزند، ولی Dio ابزارهای بیشتری مثل interceptor، لغو درخواست و آپلود با نمایش پیشرفت دارد و در پروژه‌های جدی بیشتر استفاده می‌شود.

#راه‌اندازی

یک نمونه‌ی مشترک از Dio بسازید و تنظیمات پایه را یک‌بار بدهید:

final dio = Dio(BaseOptions(
  baseUrl: 'https://api.example.com/api/v1',
  connectTimeout: const Duration(seconds: 10),
  receiveTimeout: const Duration(seconds: 20),
  headers: {'Accept': 'application/json'},
));

#مدل‌ها

پاسخ JSON را به یک کلاس Dart تبدیل کنید تا بقیه‌ی کد با نوع‌های مشخص کار کند، نه با Map خام:

class Course {
  final String id;
  final String name;
  final int price;
  const Course({required this.id, required this.name, required this.price});

  factory Course.fromJson(Map<String, dynamic> json) => Course(
        id: json['id'] as String,
        name: json['name'] as String,
        price: json['price'] as int,
      );
}

#لایه‌ی Repository

ویجت‌ها نباید مستقیم Dio صدا بزنند. یک کلاس واسط بسازید:

class CourseRepository {
  CourseRepository(this._dio);
  final Dio _dio;

  Future<List<Course>> fetchCourses() async {
    final response = await _dio.get('/courses');
    return (response.data as List)
        .map((e) => Course.fromJson(e as Map<String, dynamic>))
        .toList();
  }
}

اگر روزی آدرس یا فرمت API عوض شد، فقط همین کلاس تغییر می‌کند.

#مدیریت خطا

خطای شبکه چند نوع دارد: قطع اینترنت، timeout، و پاسخ خطا از سرور. همه را به یک پیام قابل‌فهم تبدیل کنید:

String friendlyMessage(Object error) {
  if (error is DioException) {
    switch (error.type) {
      case DioExceptionType.connectionTimeout:
      case DioExceptionType.receiveTimeout:
        return 'پاسخی از سرور نیامد. دوباره تلاش کنید.';
      case DioExceptionType.connectionError:
        return 'اتصال اینترنت را بررسی کنید.';
      default:
        final data = error.response?.data;
        if (data is Map && data['message'] is String) return data['message'];
    }
  }
  return 'خطای نامشخص رخ داد.';
}

#Interceptor برای کارهای تکراری

هر کاری که باید روی همه‌ی درخواست‌ها انجام شود (مثل افزودن هدر احراز هویت یا ثبت لاگ) را در یک interceptor بگذارید:

dio.interceptors.add(InterceptorsWrapper(
  onRequest: (options, handler) {
    final token = tokenStore.read();
    if (token != null) options.headers['Authorization'] = 'Bearer $token';
    handler.next(options);
  },
));

مقادیر حساس مثل توکن را در flutter_secure_storage نگه دارید، نه در SharedPreferences.

#نکته‌های پایانی

  • هنگام نمایش داده، سه حالت را همیشه در نظر بگیرید: در حال بارگذاری، موفق و خطا.
  • برای لیست‌های بزرگ صفحه‌بندی (pagination) را از اول در نظر بگیرید.
  • وقتی کاربر صفحه را بست، درخواست در جریان را با CancelToken لغو کنید.

با این ساختار، تغییر سرور یا افزودن یک endpoint جدید فقط یک فایل را درگیر می‌کند.

فلاتر را حرفه‌ای و پروژه‌محور یاد بگیر

دوره‌ی VIP فست فلاتر از صفر تا انتشار اپلیکیشن، با پشتیبانی مستقیم مدرس.

مشاهده‌ی دوره‌ی VIP