الخطوة 3 في تطبيق الجوال: عميل API

اربط تطبيق الدردشة لديك بالواجهة الخلفية Flask باستخدام fetch().

ما ستتعلمه

  • إرسال طلبات HTTP باستخدام fetch()
  • استخدام async/await في الشيفرة غير المتزامنة
  • التعامل مع استجابات JSON
  • معالجة الأخطاء في طلبات الشبكة

الخطوة 1: ضبط عنوان URL الأساسي لواجهة API

const API_BASE_URL = "http://10.0.2.2:5000";

أي عنوان URL تستخدم: | البيئة | عنوان URL | |---|---| | محاكي Android | http://10.0.2.2:5000 | | محاكي iOS | http://localhost:5000 | | جهاز فعلي | http://YOUR_COMPUTER_IP:5000 | | Expo web | http://localhost:5000 |

لمعرفة عنوان IP لجهاز الكمبيوتر:

# على نظام macOS/Linux
ip addr show | grep inet

# على نظام Windows
ipconfig

الخطوة 2: جلب الرسائل عند تحميل التطبيق

import { useEffect } from "react";

useEffect(() => {
  fetchMessages();
}, []);

const fetchMessages = async () => {
  try {
    const response = await fetch(`${API_BASE_URL}/api/messages`);
    const data: Message[] = await response.json();
    setMessages(data);
  } catch (err) {
    console.error("Failed to fetch messages:", err);
  }
};
  • يعمل useEffect مرة واحدة عند تحميل التطبيق (مصفوفة التبعيات [] تعني «مرة واحدة فقط»)
  • يرسل fetch() طلب GET إلى الواجهة الخلفية
  • تحلّل response.json() جسم استجابة JSON

الخطوة 3: إرسال رسالة

استبدل الدالة المؤقتة handleSend من الخطوة 2:

const handleSend = async () => {
  const text = input.trim();
  if (!text) return;

  setInput("");  // امسح حقل الإدخال فورًا
  setError(null);

  // أضف رسالة المستخدم إلى القائمة فورًا (تحديث تفاؤلي للواجهة)
  const tempUser: Message = {
    id: Date.now(),
    content: text,
    sender: "user",
  };
  setMessages((prev) => [...prev, tempUser]);

  try {
    const response = await fetch(`${API_BASE_URL}/api/chat`, {
      method: "POST",
      headers: { "Content-Type": "application/json" },
      body: JSON.stringify({ message: text }),
    });

    if (!response.ok) {
      const errData = await response.json();
      throw new Error(errData.error || "Request failed");
    }

    const data = await response.json();

    // استبدل الرسالة المؤقتة بالرسالة المؤكدة من الخادم، وأضف رد الذكاء الاصطناعي
    setMessages((prev) =>
      prev.map((m) =>
        m.id === tempUser.id ? data.user_message : m
      ).concat(data.ai_message)
    );
  } catch (err: any) {
    setError(err.message || "Failed to send message");
    // ضع علامة على الرسالة التي فشل إرسالها
    setMessages((prev) =>
      prev.map((m) =>
        m.id === tempUser.id
          ? { ...m, content: `${m.content} (failed)` }
          : m
      )
    );
  }
};

الخطوة 4: فهم fetch()

const response = await fetch(url, {
  method: "POST",                    // طريقة HTTP
  headers: {
    "Content-Type": "application/json",  // أخبر الخادم بأننا نرسل JSON
  },
  body: JSON.stringify({ message: text }),  // حوّل الكائن إلى نص JSON
});

توقف الكلمة المفتاحية await التنفيذ مؤقتًا حتى تصل الاستجابة. وبدونها ستتابع الشيفرة التنفيذ قبل أن ينتهي الطلب.

الخطوة 5: معالجة الأخطاء

try {
  // طلب شبكة
} catch (err) {
  // حدث خطأ ما — لا توجد أي استجابة (خطأ في الشبكة)
}

هناك نوعان من الأخطاء: 1. خطأ في الشبكة — تعذّر الوصول إلى الخادم (يلتقطه catch) 2. خطأ HTTP — استجاب الخادم برمز حالة خطأ (تحقّق من response.ok)

الخطوة 6: اختبار الاتصال

  1. شغّل الواجهة الخلفية: python app/__init__.py (من داخل backend/)
  2. شغّل تطبيق الجوال: npx expo start (من داخل mobile/)
  3. اكتب رسالة واضغط زر الإرسال
  4. تظهر الرسالة، ويُفترض أن يرد الذكاء الاصطناعي (إذا كنت قد أعددت OpenAI)
  5. إذا لم يرد الذكاء الاصطناعي: تحقّق من شريط الأخطاء

المشكلات الشائعة

"Network request failed" — لا يستطيع التطبيق الوصول إلى الواجهة الخلفية: - هل الواجهة الخلفية تعمل؟ - هل عنوان URL صحيح لمنصتك (محاكي أم جهاز فعلي)؟ - هل الجهازان على الشبكة نفسها؟

خطأ في تحليل JSON — الاستجابة ليست JSON صالحًا: - تحقّق من طرفية الواجهة الخلفية بحثًا عن أخطاء - اختبر باستخدام curl للتأكد من أن API يعمل