ما وراء الـ Fetch: هندسة تطبيقات جوال متكاملة (Full-Stack) وآمنة الأنواع (Type-Safe) باستخدام Expo Server Functions
توقف عن معاملة تطبيق الجوال كمواطن من الدرجة الثانية عندما يتعلق الأمر بتجربة المطور الشاملة (Full-stack DX). سأستكشف كيف تساهم Expo Server Functions في إلغاء الأكواد المتكررة (Boilerplate) لـ API وتحقيق أمان الأنواع (End-to-end type safety) في React Native.

لسنوات، شعرت هندسة تطبيقات الجوال وكأنها عالقة في بُعد موازي مقارنة بالتطور السريع للويب. بينما كان زملأونا في الويب يستمتعون بـ DX السلس لـ Next.js Server Actions و tRPC، كنا نحن في عالم React Native لا نزال نصيغ طلبات fetch يدوياً، وندير حالات التحميل (Loading states) باستخدام هوكس useEffect مكررة، والأسوأ من ذلك كله - نسخ ولصق واجهات TypeScript من مستودعات الـ Backend إلى تطبيقاتنا الأمامية (Frontend).
لقد قضيت ساعات لا تُحصى في تتبع أخطاء الانهيار (Production crashes) الناتجة عن تعارض بسيط بين استجابة JSON والواجهة المتوقعة لها. لكن اللعبة تغيرت الآن. مع تقديم Expo Server Functions، بدأنا أخيراً في تجاوز مرحلة الـ Fetch.
المشكلة: الانقسام الكبير في الـ API
تاريخياً، يُعتبر تطبيق الجوال عميلاً (Client) معزولاً. أنت تبني واجهة المستخدم، وتحدد الأنواع (Types)، وتأمل ألا يغير فريق الـ API (أو مجلد الـ Backend الخاص بك) اسم حقل دون إخبارك. لقد حاولنا سد هذه الفجوة باستخدام:
- GraphQL/Apollo: عظيمة، لكنها ثقيلة وتتطلب الكثير من الأكواد المتكررة (Boilerplate).
- tRPC: ممتازة لأمان الأنواع، لكنها تتطلب إعدادات خاصة وقد يكون من الصعب تحسينها للبيئات الأصلية (Native environments).
- Swagger/OpenAPI generators: أفضل من لا شيء، لكن الـ DX فيها غير سلس.
تعالج Expo Server Functions هذه المشكلة من خلال معاملة منطق الـ Backend كجزء من منطق تطبيقك، وليس ككيان بعيد يتعين عليك التفاوض معه.
الطفرة: RPC بدون أكواد متكررة (Zero-Boilerplate RPC)
في تجربتي المعمارية الأخيرة، قمت بنقل ميزة أساسية من نهج REST التقليدي إلى Expo Server Function. كان التحول في الإنتاجية فورياً.
بدلاً من تعريف مسار (Route)، ومتحكم (Controller)، ومخطط تحقق (Validation schema) على السيرفر، ثم fetcher وتعريف للأنواع على الكلاينت، أنت ببساطة تكتب دالة (Function).
على الكلاينت، لن تستخدم axios ولا حتى fetch. أنت ببساطة تقوم باستيراد الدالة. تتولى Expo المهمة الصعبة المتمثلة في تحويل ذلك الاستيراد إلى استدعاء RPC آمن الأنواع (Type-safe).
لماذا يهم هذا كبار المهندسين (Senior Engineers)؟
كمهندسين، نحن لا نبحث فقط عن "تقنيات رائعة"؛ بل نبحث عن تقليل المخاطر وزيادة السرعة. إليك سبب اعتبار هذا طفرة من منظور هندسي:
- المصدر الوحيد للحقيقة (Single Source of Truth): تتم مشاركة الأنواع الخاصة بك بشكل ضمني. إذا قمت بتغيير حقل
quantityإلى سلسلة نصية في مخطط Zod، فسيظهر فوراً خطأ أحمر في كود الكلاينت. هذا يقضي على فئة كاملة من أخطاء وقت التشغيل (Runtime errors). - الأمان حسب التصميم (Security by Design): لأن هذه الدوال تعمل على السيرفر، يمكنك استخدام متغيرات البيئة (مثل مفاتيح API السرية) بأمان دون الكشف عنها أبداً في الملف البرمجي (Binary) المرسل إلى متجر التطبيقات.
- تقليل حجم الحزمة (Reduced Bundle Size): يظل المنطق الموجود داخل دالات السيرفر على السيرفر. أنت تشحن كوداً أقل لجهاز المستخدم، وهو أمر بالغ الأهمية للأداء وسرعة بدء التشغيل.
دروس من الواقع العملي
من الأمور التي اكتشفتها أثناء التنفيذ هي أنه على الرغم من أنها تبدو وكأنها استدعاء لدالة محلية، إلا أنها لا تزال طلباً عبر الشبكة. لا يزال يتعين عليك التعامل مع حالات انتهاء الوقت (Timeouts) وحالات عدم الاتصال بالإنترنت. أنصح بدمج Expo Server Functions مع أداة مثل TanStack Query. يتيح لك ذلك تغليف استدعاء دالة السيرفر في Hook يدير التخزين المؤقت (Caching)، وإعادة المحاولة، وحالات التحميل تلقائياً.
الخلاصة
تمثل Expo Server Functions نقلة نوعية في التطوير الأصلي (Native development). نحن نرى أخيراً توحيداً للتقنيات (Unification of the stack). بالنسبة لكبار المطورين، هذا يعني قضاء وقت أقل في بناء "البنية التحتية" (Plumbing) ومزيداً من الوقت في هندسة المنتج الفعلي.
إذا لم تجربها بعد، أنصحك بشدة بإعادة بناء مكون صغير وكثيف البيانات باستخدامها. ستجد أنه عندما تتلاشى الحدود بين الكلاينت والسيرفر، فإن قدرتك على تقديم ميزات قوية ستتضاعف بشكل هائل.