دليلك الشامل لتحويل JSON إلى كائنات Dart للمبتدئين
هل سبق لك أن جلبت بيانات من الإنترنت عبر API في تطبيق Flutter الخاص بك، لكنك وجدت نفسك تتعامل مع سلاسل نصية معقدة من JSON؟ إذا كنت مبتدئًا في تطوير التطبيقات، قد يبدو هذا الأمر مربكًا في البداية. لكن لا تقلق! في هذا الدليل الشامل، سنشرح التسلسل (Serialization) في Flutter خطوة بخطوة، مع أمثلة عملية بسيطة ومفصلة. سنغطي كيفية تحويل JSON إلى كائنات Dart، الطرق اليدوية والآلية، وأفضل الممارسات لجعل كودك نظيفًا وفعالًا. إذا كنت تبحث عن “التسلسل في Flutter” أو “تحويل JSON إلى Dart في Flutter” أو “json_serializable شرح بالعربي”، فأنت في المكان الصحيح. هذا المقال مصمم خصيصًا للمبتدئين، مع تفسيرات واضحة وكود قابل للتجربة مباشرة.
في نهاية المقال، ستكون قادرًا على:
- فهم ما هو التسلسل ولماذا هو ضروري في Flutter.
- كتابة تحويل يدوي لـ JSON.
- استخدام مكتبة json_serializable للتوليد الآلي.
- تجنب الأخطاء الشائعة وتطبيق أفضل الممارسات.
دعونا نبدأ الرحلة معًا، وسنبسط كل شيء ليصبح سهل الفهم!
ما هو التسلسل (Serialization) في Flutter ولماذا نحتاجه؟
للمبتدئين، دعونا نبدأ بتعريف بسيط: التسلسل (Serialization) هو عملية تحويل البيانات من صيغة واحدة إلى أخرى. في سياق Flutter، يعني ذلك تحويل بيانات JSON (التي تأتي عادةً من الإنترنت أو قواعد البيانات) إلى كائنات Dart قابلة للاستخدام مباشرة في كودك. والعكس صحيح: تحويل كائنات Dart إلى JSON لإرسالها إلى الخادم.
- Serialization: تحويل كائن Dart إلى JSON (مثلًا عند إرسال بيانات تسجيل مستخدم إلى API).
- Deserialization: تحويل JSON إلى كائن Dart (مثلًا عند استقبال قائمة منتجات من الخادم).
لماذا نحتاج إلى التسلسل في Flutter؟
بدون التسلسل، ستتعامل مع خرائط (Maps) غامضة مثل Map<String, dynamic>، مما يؤدي إلى أخطاء برمجية شائعة مثل الوصول إلى حقل غير موجود. إليك الفوائد الرئيسية:
- تنظيم البيانات: بدل التعامل مع سلاسل نصية، تحصل على كائنات منظمة مثل
RecipeأوUserمع خصائص محددة (مثلtitleأوemail). - تقليل الأخطاء: الكائنات تكون strongly typed، مما يمنع أخطاء الإملاء أو النوع (مثل محاولة قراءة string كـ int).
- سهولة الصيانة: إذا تغير شكل JSON من الـ API، يكفي تعديل الـ Model دون تغيير الكود في كل مكان.
- تحسين الأداء: في المشاريع الكبيرة، يساعد التسلسل الآلي في تسريع التطوير.
تخيل أنك تبني تطبيقًا للمتاجر الإلكترونية: بدون التسلسل، ستكتب كودًا طويلًا لقراءة كل حقل من JSON يدويًا.
معه، يصبح الأمر تلقائيًا وأنظف!
التحويل اليدوي لـ JSON في Flutter: خطوات بسيطة للمبتدئين
إذا كنت جديدًا، ابدأ بالطريقة اليدوية لفهم الأساسيات قبل الانتقال إلى الآلي. لنفترض أن لديك API يعيد بيانات وصفة طعام بصيغة JSON:
{
"id": 1,
"title": "بيتزا مارغريتا",
"image_url": "https://example.com/pizza.jpg",
"ingredients": ["طماطم", "جبنة", "عجينة"]
}
الخطوة 1: تعريف نموذج الكائن (Model Class)
أنشئ فئة Dart تمثل البيانات:
class Recipe {
final int id;
final String title;
final String imageUrl;
final List<String> ingredients;
Recipe({
required this.id,
required this.title,
required this.imageUrl,
required this.ingredients,
});
// دالة لتحويل JSON إلى كائن Dart (Deserialization)
factory Recipe.fromJson(Map<String, dynamic> json) {
return Recipe(
id: json['id'] as int, // تحقق من النوع لتجنب الأخطاء
title: json['title'] as String,
imageUrl: json['image_url'] as String, // لاحظ تغيير الاسم إذا اختلف
ingredients: List<String>.from(json['ingredients'] as List), // للقوائم
);
}
// دالة لتحويل كائن Dart إلى JSON (Serialization)
Map<String, dynamic> toJson() {
return {
'id': id,
'title': title,
'image_url': imageUrl,
'ingredients': ingredients,
};
}
}
الخطوة 2: استخدام النموذج في الكود
افترض أنك جلبت JSON من API (كما في مقال الشبكات السابق):
import 'dart:convert';
void main() {
final jsonString = '''
{
"id": 1,
"title": "بيتزا مارغريتا",
"image_url": "https://example.com/pizza.jpg",
"ingredients": ["طماطم", "جبنة", "عجينة"]
}
''';
final jsonData = jsonDecode(jsonString); // تحويل String إلى Map
final recipe = Recipe.fromJson(jsonData); // تحويل Map إلى Recipe
print('العنوان: ${recipe.title}'); // بيتزا مارغريتا
print('المكونات: ${recipe.ingredients.join(', ')}'); // طماطم, جبنة, عجينة
// الآن، لإرسال البيانات: تحويل إلى JSON
final jsonOutput = jsonEncode(recipe.toJson());
print(jsonOutput); // يطبع JSON جديد
}
للمبتدئين: هذه الطريقة بسيطة، لكنها تتطلب كتابة كود إضافي لكل حقل. إذا كان لديك نماذج معقدة (مثل قوائم داخل قوائم)، قد تكون عرضة للأخطاء. هنا يأتي دور الطريقة الآلية!
التوليد الآلي للتسلسل باستخدام json_serializable في Flutter
عندما يكبر مشروعك، يصبح الكتابة اليدوية مرهقة ومملة. الحل: مكتبة json_serializable التي تولد دوال fromJson وtoJson تلقائيًا باستخدام build_runner. هذه الطريقة توفر الوقت وتقلل الأخطاء، خاصة في المشاريع الكبيرة.
الخطوة 1: تثبيت الحزم اللازمة
أضف إلى pubspec.yaml:
dependencies:
json_annotation: ^4.9.0 # للتعليقات
dev_dependencies:
json_serializable: ^6.8.0 # للتوليد
build_runner: ^2.4.7 # لتشغيل التوليد
ثم شغل: flutter pub get.
الخطوة 2: تعريف النموذج مع التعليقات
import 'package:json_annotation/json_annotation.dart';
part 'recipe.g.dart'; // سيتم توليد هذا الملف
@JsonSerializable()
class Recipe {
final int id;
final String title;
@JsonKey(name: 'image_url') // لتغيير اسم الحقل إذا اختلف في JSON
final String imageUrl;
final List<String> ingredients;
Recipe({
required this.id,
required this.title,
required this.imageUrl,
required this.ingredients,
});
factory Recipe.fromJson(Map<String, dynamic> json) => _$RecipeFromJson(json);
Map<String, dynamic> toJson() => _$RecipeToJson(this);
}
الخطوة 3: توليد الكود الآلي
شغل الأمر: flutter pub run build_runner build --delete-conflicting-outputs
سيولد ملف recipe.g.dart يحتوي على الدوال التلقائية. الآن، يمكنك استخدام fromJson كما في الطريقة اليدوية!
فيديو للايضاح أكثر
الخطوة 4: التعامل مع الحقول المعقدة
إذا كان لديك قوائم أو كائنات داخلية، استخدم @JsonSerializable() على كل فئة. على سبيل المثال، إذا كان ingredients كائنًا، أنشئ فئة Ingredient وأضفها إلى Recipe.
للمبتدئين: هذه الطريقة تتجنب الأخطاء الإملائية، وتدعم أنواعًا معقدة مثل DateTime أو Enums بتعليقات إضافية.
أيهما أفضل: التحويل اليدوي أم json_serializable في Flutter؟
- التحويل اليدوي: مناسب للمشاريع الصغيرة أو عند الحاجة لتحكم كامل في التحويل (مثل معالجة حالات خاصة). ميزته: بسيط وبدون حزم إضافية. عيبه: مرهق في النماذج الكبيرة.
- json_serializable: الأفضل للمشاريع المتوسطة والكبيرة، حيث يوفر الوقت ويقلل الأخطاء. ميزته: توليد تلقائي مع دعم للتحديثات. عيبه: يتطلب build_runner، وقد يولد كودًا إضافيًا.
نصيحة للمبتدئين: ابدأ باليدوي للتعلم، ثم انتقل إلى الآلي للكفاءة.
أفضل الممارسات للتسلسل في Flutter (Best Practices)
لجعل كودك نظيفًا وسهل الصيانة، اتبع هذه النصائح:
- استخدم أسماء واضحة للنماذج: مثل
UserModelأوProduct، لتكون مفهومة. - حافظ على التوافق مع الـ API: إذا اختلف اسم الحقل في JSON (مثل snake_case مقابل camelCase)، استخدم
@JsonKey(name: 'api_name')للتكيف دون تغيير الكود. - نقل الكود إلى مجلد models/: لتنظيم المشروع، وضع جميع النماذج في مجلد واحد.
- فصل المنطق عن الواجهة: لا تضع كود التسلسل داخل الـ Widget؛ استخدم طبقة services أو providers.
- التعامل مع الحقول الاختيارية: استخدم
nullableمثلString?للحقول التي قد تكون null، وتحقق منها لتجنب الأخطاء. - الاختبار: اختبر الدوال fromJson وtoJson باستخدام وحدات اختبار للتأكد من الدقة.
الأخطاء الشائعة في التسلسل في Flutter وكيفية تجنبها
كمبتدئ، قد تواجه هذه المشكلات:
- خطأ في أنواع البيانات: مثل محاولة قراءة int كـ String. الحل: استخدم as للتحقق، أو استخدم json_serializable للتعامل التلقائي.
- حقول مفقودة: إذا لم يكن الحقل موجودًا في JSON، قد يحدث خطأ. الحل: استخدم
json['field'] ?? defaultValue. - قوائم معقدة: إذا كانت ingredients قائمة كائنات، أنشئ نموذجًا داخليًا واستخدم map للتحويل.
- أداء ضعيف: في قوائم كبيرة، تجنب jsonDecode داخل build؛ قم بها مرة واحدة في initState.
الخاتمة: ابدأ في تطبيق التسلسل في مشاريع Flutter الخاصة بك
في هذا الدليل، تعلمنا كل شيء عن التسلسل في Flutter: من التعريف الأساسي إلى التحويل اليدوي والآلي باستخدام json_serializable، مع أفضل الممارسات والأخطاء الشائعة. الآن، أنت جاهز لتحويل بيانات JSON إلى كائنات Dart بكفاءة، مما يجعل تطبيقاتك أكثر تنظيمًا وأمانًا. جرب الأمثلة في مشروعك التالي، وستلاحظ الفرق في سهولة التطوير!
