في أي تطبيق حقيقي، يجب عليك تحديد **نموذج البيانات (Model)** الذي يعبّر عن الكائنات في تطبيقك—مثل المستخدمين أو المنتجات—ثم التفكير في كيفية
تخزين هذه البيانات محليًا مؤقتًا أو دائمًا، وأخيرًا في كيفية جلبها أو إرسالها إلى الخادم عبر **Web APIs**. سنغطي في هذا القسم:
- إنشاء نموذج البيانات مع `fromJson` و `toJson`
- التخزين المحلي باستخدام
SharedPreferences
- مفهوم الـ API وأنواع الطلبات (GET، POST، PUT، DELETE)
- جلب البيانات من API وعرضها في الواجهة باستخدام
FutureBuilder
- إرسال البيانات وتحديثها عبر POST و PUT
- نصائح لاختبار الـ API باستخدام Postman
📁 1. نموذج البيانات (Data Model)
أول خطوة هي إنشاء نموذج Dart يعكس بنية البيانات القادمة من الخادم أو البيانات التي تريد إرسالها.
هذا النموذج يجب أن يحتوي على دوال fromJson لتحويل JSON إلى كائن Dart، وtoJson لتحويل كائن Dart إلى JSON عند الإرسال.
📄 ملف: lib/models/user_model.dart
class User {
final int? id;
final String name;
final String email;
User({
this.id,
required this.name,
required this.email,
});
/// تحويل JSON إلى كائن Dart
factory User.fromJson(Map<String, dynamic> json) {
return User(
id: json['id'],
name: json['name'],
email: json['email'],
);
}
/// تحويل كائن Dart إلى JSON (للإرسال إلى الخادم)
Map<String, dynamic> toJson() {
return {
'name': name,
'email': email,
};
}
}
💾 2. التخزين المحلي باستخدام SharedPreferences
في بعض الأحيان ترغب في حفظ تفضيلات المستخدم أو بيانات صغيرة مثل الثيم أو حالة تسجيل الدخول محليًا دون الحاجة لقاعدة بيانات كاملة.
SharedPreferences يسمح بتخزين أزواج مفتاح-قيمة (String) بطرق متزامنة وبسيطة.
📄 ملف: lib/services/local_storage.dart
import 'package:shared_preferences/shared_preferences.dart';
class LocalStorage {
/// حفظ قيمة نصية بالمفتاح المحدد
static Future<void> saveData(String key, String value) async {
final prefs = await SharedPreferences.getInstance();
await prefs.setString(key, value);
}
/// استرجاع قيمة نصية بناءً على المفتاح
static Future<String?> getData(String key) async {
final prefs = await SharedPreferences.getInstance();
return prefs.getString(key);
}
/// مسح جميع البيانات المخزنة
static Future<void> clearAll() async {
final prefs = await SharedPreferences.getInstance();
await prefs.clear();
}
}
✅ مثال توضيحي لحفظ واسترجاع الثيم:
// حفظ الثيم (مثلاً: 'dark' أو 'light')
await LocalStorage.saveData('theme', 'dark');
// استرجاع الثيم عند تشغيل التطبيق
final storedTheme = await LocalStorage.getData('theme');
print('الثيم المخزن هو: $storedTheme');
🌐 3. ما هو الـ API وكيفية استهلاكه
API (واجهة برمجة التطبيقات) هو واجهة تتيح لتطبيق Flutter الخاص بك التواصل مع خادم خارجي.
غالبًا ما تكون الـ APIs مبنية كنقاط نهاية (Endpoints) على خادم يستخدم بروتوكولات HTTP، وتستقبل الطلبات في صورة GET أو POST أو PUT أو DELETE، وتُرجع استجابات بصيغة JSON.
📦 حالات استخدام (Use Cases)
- جلب قائمة المنتجات وعرضها في تطبيق متجر إلكتروني
- إنشاء حساب مستخدم جديد أو تسجيل الدخول
- عرض بيانات الطقس من خادم خارجي
- تنفيذ تحديث أو حذف على سجل في قاعدة بيانات الخادم
- تكامل مع خدمات دفع إلكتروني (Stripe، PayPal)
🛠️ هيكلية نموذجية للـ API
عندما ترسل طلبًا GET إلى نقطة النهاية /products مثلاً:
GET https://api.example.com/products
Response:
[
{ "id": 1, "name": "Laptop", "price": 1299.99 },
{ "id": 2, "name": "Mouse", "price": 19.99 }
]
📲 4. جلب البيانات من API (GET)
في Flutter نستخدم مكتبة http لإرسال الطلبات.
المثال التالي يوضح كيفية جلب قائمة المستخدمين وتحويل كل عنصر إلى كائن User (النموذج الذي أنشأناه سابقًا).
📄 ملف: lib/services/api_service.dart
import 'package:http/http.dart' as http;
import 'dart:convert';
import '../models/user_model.dart';
class ApiService {
static const String _baseUrl = 'https://api.example.com';
/// جلب قائمة المستخدمين من الخادم
static Future<List<User>> fetchUsers() async {
final response = await http.get(Uri.parse('$_baseUrl/users'));
if (response.statusCode == 200) {
List<dynamic> data = jsonDecode(response.body);
return data.map((json) => User.fromJson(json)).toList();
} else {
throw Exception('فشل في تحميل المستخدمين: ${response.statusCode}');
}
}
}
📦 عرض البيانات باستخدام FutureBuilder
بعد جلب البيانات، نستخدم FutureBuilder لعرضها في واجهة المستخدم:
FutureBuilder<List<User>>(
future: ApiService.fetchUsers(),
builder: (context, snapshot) {
if (snapshot.connectionState == ConnectionState.waiting) {
return Center(child: CircularProgressIndicator());
} else if (snapshot.hasError) {
return Center(child: Text('خطأ: \${snapshot.error}'));
} else if (!snapshot.hasData || snapshot.data!.isEmpty) {
return Center(child: Text('لا توجد بيانات'));
} else {
final users = snapshot.data!;
return ListView.builder(
itemCount: users.length,
itemBuilder: (context, index) {
return ListTile(
title: Text(users[index].name),
subtitle: Text(users[index].email),
);
},
);
}
},
)
📝 5. إرسال وتحديث البيانات (POST / PUT)
بعد أن أصبح نموذج البيانات جاهزًا، يمكننا إرسال كائن User جديد إلى الخادم أو تحديث أحد المستخدمين الموجودين باستخدام POST و PUT.
📤 5.1 إرسال مستخدم جديد (POST)
نستخدم دالة http.post مع تحويل الكائن إلى JSON عبر user.toJson():
Future<void> createUser(User user) async {
final response = await http.post(
Uri.parse('https://api.example.com/users'),
headers: {'Content-Type': 'application/json'},
body: jsonEncode(user.toJson()),
);
if (response.statusCode == 201) {
print('تمت إضافة المستخدم بنجاح');
} else {
throw Exception('فشل في إرسال المستخدم: ${response.statusCode}');
}
}
🔄 5.2 تعديل مستخدم موجود (PUT)
لتحديث بيانات مستخدم محدد، نمرر معرف المستخدم في الـ URL:
Future<void> updateUser(User user) async {
final response = await http.put(
Uri.parse('https://api.example.com/users/\${user.id}'),
headers: {'Content-Type': 'application/json'},
body: jsonEncode(user.toJson()),
);
if (response.statusCode == 200) {
print('تم تحديث بيانات المستخدم');
} else {
throw Exception('فشل في التحديث: ${response.statusCode}');
}
}
❌ 5.3 حذف مستخدم (DELETE)
إذا أردت حذف سجل مستخدم من الخادم، تستخدم http.delete مع معرف المستخدم:
Future<void> deleteUser(int id) async {
final response = await http.delete(
Uri.parse('https://api.example.com/users/\$id'),
);
if (response.statusCode == 200) {
print('تم حذف المستخدم');
} else {
throw Exception('فشل في الحذف: ${response.statusCode}');
}
}
🧪 6. اختبار الـ API عبر Postman
قبل ربط الـ API بتطبيقك، من الأفضل التأكد من عمله باستخدام Postman:
- افتح Postman وأنشئ طلب جديد (GET/POST/PUT/DELETE).
- أدخل رابط الـ API الصحيح، مثل
https://api.example.com/users.
- إذا كان الطلب يتطلب Body (مثل POST/PUT)، انتقل إلى تبويب Body واختر
raw ثم JSON وأدخل البيانات.
- اضغط زر "Send" وراقب الاستجابة (Response).
- تأكد من كود الحالة (Status Code) والرد JSON قبل دمج الكود في تطبيقك.
📌 ملاحظات هامة:
- تأكد من إعداد الــ
headers بالشكل الصحيح: 'Content-Type': 'application/json'.
- استخدم
print(response.body) في Flutter أثناء التطوير لرؤية JSON المستلم.
- عند استخدام بيانات كبيرة أو متعددة الاستهلاك، فكر في إضافة التخزين المؤقت (caching).
📌 خلاصة واستنتاجات
- ابدأ دائمًا بتعريف نموذج البيانات (Model) المناسب لكائناتك.
- التخزين المحلي عبر
SharedPreferences مناسب للبيانات البسيطة مثل الثيم وتفضيلات المستخدم.
- استخدم مكتبة
http لجلب البيانات (GET) وعرضها في الواجهة باستخدام FutureBuilder.
- لإرسال أو تحديث البيانات، اعتمد على
http.post و http.put مع تحويل النموذج إلى JSON.
- قبل دمج أي نقطة نهاية (Endpoint)، اختبرها أولاً باستخدام Postman لضمان عملها بصورة صحيحة.
- يمكنك إضافة مزيد من المرونة باستخدام Provider أو GetX لإدارة التحميل وحالة الخطأ وتنظيم الكود.