GraphQL: كيف أنقذنا واجهاتنا من جحيم الطلبات المتعددة والبيانات المهدورة؟

يا أهلاً بكم يا جماعة، معكم أبو عمر.

قبل كم سنة، كنا شغالين على مشروع كبير، تطبيق فيه لوحة تحكم معقدة شوي. الفكرة كانت بسيطة على الورق: صفحة رئيسية تعرض للمستخدم ملخص حسابه، آخر منشوراته، والتعليقات على هاي المنشورات، وقائمة أصدقائه المتصلين حالياً. كل شيء تمام لحد هون.

لكن لما بلشنا شغل على الواجهة الأمامية (Frontend)، بدأت المشاكل تظهر. عشان نعرض هاي الصفحة، كان فريق الواجهة الأمامية لازم يعمل طلب (API call) عشان يجيب معلومات المستخدم. وبعد ما تيجي المعلومات، يعمل طلب ثاني عشان يجيب منشوراته. وبعدين، لكل منشور، ممكن يحتاج يعمل طلب ثالث عشان يجيب التعليقات! الوضع صار فوضى، والصفحة بتحمّل ببطء شديد. أذكر يومها دخل عليّ مدير المشروع، وجهه أحمر، وقلي: “أبو عمر، شو القصة؟ التطبيق أبطأ من سلحفاة طالعة جبل!”. يومها، عرفت إنه لازم نلاقي حل جذري، مش مجرد ترقيع. وهنا بدأت رحلتنا مع GraphQL.

ما هو “جحيم الـ API” الذي كنا نعيشه؟ (فهم المشكلة)

قبل ما نحكي عن الحل، خلينا نفصّل المشكلة اللي كنا (والكثير منكم) بنعيشها مع معمارية REST API التقليدية. المشكلة بتتلخص في مصطلحين رئيسيين: الجلب الزائد والجلب الناقص.

مشكلة الجلب الزائد (Over-fetching)

تخيل إنك بدك تعرض قائمة بأسماء المستخدمين وصورهم الشخصية فقط. في عالم REST، غالباً ما يكون عندك نقطة نهاية (endpoint) مثل /api/users. لما تطلب من هاي النقطة، بترجعلك كل المعلومات عن كل مستخدم: الاسم، الصورة، البريد الإلكتروني، تاريخ الميلاد، آخر مرة سجل دخوله فيها، وعشر حقول ثانية ما إلك فيها أي لزوم في هاي الصفحة.

هذا هو الـ Over-fetching: أنت بتجيب بيانات أكثر بكثير من اللي بتحتاجها. هذا يعني إهدار في استهلاك باقة الإنترنت للمستخدم (خصوصاً على الموبايل)، وزيادة في زمن تحميل الصفحة بدون أي داعي.

كنا نطلب اسم المستخدم، فترجع لنا الـ API قصة حياته كاملة. إهدار واضح للموارد والوقت.

مشكلة الجلب الناقص (Under-fetching) والطلبات المتتالية

هاي المشكلة هي الوجه الآخر للعملة، وهي اللي كانت سبب بطء تطبيقنا الكارثي. الـ Under-fetching معناه إن نقطة النهاية الواحدة ما بتعطيك كل البيانات اللي بتحتاجها، فبتضطر تعمل طلبات إضافية.

نرجع لمثالنا الأول (صفحة لوحة التحكم):

  • الطلب الأول: GET /api/users/{userId} عشان نجيب معلومات المستخدم الأساسية.
  • الطلب الثاني: GET /api/users/{userId}/posts عشان نجيب قائمة منشوراته.
  • الطلب الثالث (وربما الرابع والخامس): GET /api/posts/{postId}/comments لكل منشور بدنا نعرض تعليقاته.

هذا الشلال من الطلبات (Request Waterfall) هو وصفة أكيدة لتطبيق بطيء وتجربة مستخدم محبطة. الواجهة الأمامية بتضل تستنى كل طلب يخلص عشان تبدأ باللي بعده.

المنقذ GraphQL: كيف يعمل السحر؟

بعد ما تشخصت المشكلة، كان الحل واضحاً: لازم نغير طريقة تواصل الواجهة الأمامية مع الخلفية. وهنا يأتي دور GraphQL، وهي ليست لغة برمجة أو إطار عمل، بل هي لغة استعلام (Query Language) للـ API.

الفكرة عبقرية وبسيطة: بدلاً من وجود عشرات نقاط النهاية الثابتة في الـ Backend، صار عنا نقطة نهاية واحدة فقط (عادة /graphql)، والواجهة الأمامية هي اللي بتحدد شكل البيانات اللي بدها إياها بالضبط.

العميل هو الملك: اطلب ما تحتاجه بالضبط

مع GraphQL، الواجهة الأمامية صارت هي “الملك”. هي اللي بتكتب “طلب” أو “استعلام” (Query) بتوصف فيه البيانات اللي محتاجاها بالحرف، والسيرفر بيرجع هاي البيانات فقط، لا زيادة ولا نقصان.

لحل مشكلة لوحة التحكم تبعتنا، بدل شلال الطلبات، صرنا نبعث طلب واحد زي هيك:


query GetDashboardData {
  user(id: "123") {
    name
    avatarUrl
    posts(last: 5) {
      id
      title
      comments(first: 3) {
        text
        author {
          name
        }
      }
    }
    friends(online: true) {
      name
    }
  }
}

شوفوا الجمال! بطلب واحد، قدرنا نجيب:

  • اسم المستخدم وصورته.
  • آخر 5 منشورات له (عنوان كل منشور ورقمه).
  • أول 3 تعليقات على كل منشور من هاي المنشورات (مع اسم كاتب التعليق).
  • قائمة الأصدقاء المتصلين حالياً.

والسيرفر راح يرجع لنا ملف JSON مطابق تماماً لشكل الطلب اللي بعثناه. لا Over-fetching ولا Under-fetching. طلب واحد، إجابة واحدة، وانتهت القصة.

REST vs. GraphQL: مواجهة عملية

عشان الصورة تكون أوضح، خلينا نقارن بين الطريقتين في سيناريو عملي من خلال كود الواجهة الأمامية.

السيناريو: عرض صفحة ملف شخصي للمستخدم مع منشوراته

الطريقة التقليدية (REST)

في الواجهة الأمامية (باستخدام JavaScript مثلاً)، الكود راح يكون شبيه بهذا:


async function getUserProfile(userId) {
  try {
    // الطلب الأول للحصول على معلومات المستخدم
    const userResponse = await fetch(`/api/users/${userId}`);
    const userData = await userResponse.json();

    // الطلب الثاني للحصول على منشورات المستخدم
    const postsResponse = await fetch(`/api/users/${userId}/posts`);
    const postsData = await postsResponse.json();

    // دمج البيانات لعرضها في الواجهة
    const profileData = { ...userData, posts: postsData };
    return profileData;

  } catch (error) {
    console.error("Failed to fetch profile data:", error);
  }
}

لاحظوا كيف عنا طلبين منفصلين، ولازم ننتظر الأول يخلص عشان (ممكن) نبدأ الثاني، وبعدين ندمج البيانات يدوياً.

الطريقة الحديثة (GraphQL)

مع GraphQL، الوضع مختلف تماماً. الكود أبسط وأكثر فعالية:


async function getUserProfile(userId) {
  const query = `
    query GetUserProfile($id: ID!) {
      user(id: $id) {
        name
        email
        bio
        posts {
          title
          createdAt
        }
      }
    }
  `;

  try {
    const response = await fetch('/graphql', {
      method: 'POST',
      headers: { 'Content-Type': 'application/json' },
      body: JSON.stringify({ 
        query: query,
        variables: { id: userId } 
      }),
    });

    const result = await response.json();
    return result.data.user; // البيانات جاهزة ومكتملة

  } catch (error) {
    console.error("Failed to fetch profile data:", error);
  }
}

طلب واحد فقط. الواجهة الأمامية وصفت البيانات اللي بدها إياها، والسيرفر نفّذ. لا وجع راس ولا شلالات.

نصيحة من أبو عمر

يا جماعة الخير، الفائدة الكبرى لـ GraphQL مش بس تقليل عدد الطلبات. الفائدة الحقيقية هي في استقلالية فريق الواجهة الأمامية. ما عدنا بحاجة نركض ورا فريق الـ Backend كل مرة بدنا حقل زيادة أو تعديل بسيط في البيانات. المطور بكتب الـ Query اللي بتخدمه، وخلصنا. هذا بيسرّع عملية التطوير بشكل لا يصدق، وبيخلي كل فريق يركز على شغله. “افصل الشغل، بتكسب الكل”.

متى لا يكون GraphQL هو الحل؟ (نظرة متوازنة)

بالرغم من كل حبي لـ GraphQL، من الغلط نحكي إنها الحل لكل المشاكل. في حالات معينة، قد تكون REST API التقليدية خياراً أفضل أو أبسط:

  • الـ APIs البسيطة جداً: إذا كان كل تطبيقك عبارة عن 5 نقاط نهاية بسيطة، قد يكون تبني GraphQL تعقيداً لا داعي له.
  • التعامل مع الملفات: رفع الملفات (File Uploads) في REST مباشر وبسيط (multipart/form-data). في GraphQL، الأمر ممكن لكنه يحتاج لإعدادات إضافية ومكتبات خاصة.
  • التخزين المؤقت (Caching): الـ Caching في REST على مستوى HTTP واضح ومُدمج. بما أن GraphQL تستخدم طلبات POST على نقطة نهاية واحدة، فإن آليات التخزين المؤقت على مستوى الشبكة (Network-level Caching) تصير أصعب وتحتاج لحلول على مستوى العميل (Client-side).
  • المنحنى التعليمي: تبني GraphQL في فريقك يتطلب وقتاً لتعلم المفاهيم الجديدة (Schemas, Resolvers, Types) من قبل فريق الـ Backend.

خلاصة القول ونصيحة أخيرة 💡

في النهاية، GraphQL كانت بالنسبة لفريقنا طوق النجاة اللي أنقذنا من فوضى الطلبات المتعددة وبطء التطبيقات. منحتنا المرونة والقوة لتطوير واجهات سريعة وفعالة، وحسّنت من تجربة المطورين بشكل كبير.

هل هذا يعني أن ترمي كل REST APIs اللي عندك وتتحول لـ GraphQL اليوم؟ طبعاً لا.

نصيحتي العملية: ابدأ صغيراً. حدد جزءاً من تطبيقك يعاني بشدة من مشكلة الـ “شلال” أو الـ Over-fetching. جرب بناء طبقة GraphQL فوق خدماتك الحالية (GraphQL can wrap existing REST APIs). راقب الأداء، وقسّم الفوائد بنفسك. الخطوة الأولى هي الأصعب، لكن النتائج، صدقني، تستحق العناء.

يلا، شدوا حيلكم، وسلامتكم!

أبو عمر

سجل دخولك لعمل نقاش تفاعلي

كافة المحادثات خاصة ولا يتم عرضها على الموقع نهائياً

آراء من النقاشات

لا توجد آراء منشورة بعد. كن أول من يشارك رأيه!

آخر المدونات

الحوسبة السحابية

كنا ندفع ثمن الخوادم الخاملة: كيف أنقذتنا ‘الحوسبة بلا خوادم’ (Serverless) من جحيم التكاليف المهدرة؟

في هذه المقالة، أشارككم قصة حقيقية من تجربتي كمطور برمجيات عن كيفية انتقالنا من الخوادم التقليدية باهظة الثمن إلى معمارية الحوسبة بلا خوادم (Serverless). سنغوص...

21 مايو، 2026 قراءة المزيد
التوسع والأداء العالي والأحمال

كانت طلباتنا تتعثر في أوقات الذروة: كيف أنقذتنا ‘طوابير الرسائل’ (Message Queues) من جحيم الاختناقات؟

أشارككم قصة حقيقية من قلب المعركة البرمجية، كيف كاد تطبيقنا أن ينهار تحت ضغط المستخدمين في يوم إطلاق مهم، وكيف كانت "طوابير الرسائل" (Message Queues)...

21 مايو، 2026 قراءة المزيد
التكنلوجيا المالية Fintech

كانت بياناتنا المالية سجينة البنوك: كيف حررتها واجهات ‘الصيرفة المفتوحة’ (Open Banking)؟

من واقع تجربتي كمبرمج، كانت بياناتنا المالية حبيسة جدران البنوك الرقمية. في هذه المقالة، أسرد لكم كيف حولت واجهات برمجة التطبيقات للصيرفة المفتوحة (Open Banking)...

21 مايو، 2026 قراءة المزيد
البنية التحتية وإدارة السيرفرات

كانت سجلاتنا متناثرة وضائعة: كيف أنقذنا التجميع المركزي (ELK/Loki) من جحيم تتبع الأخطاء؟

أشارككم قصة حقيقية من قلب المعركة البرمجية، كيف انتقلنا من فوضى السجلات المتناثرة على عشرات الخوادم إلى نظام مركزي أنقذنا من جحيم تتبع الأخطاء. مقالة...

21 مايو، 2026 قراءة المزيد
ادارة الفرق والتنمية البشرية

كانت ساحة لتبادل الاتهامات: كيف أنقذتنا ‘ثقافة ما بعد الحوادث عديمة اللوم’ من جحيم الخوف؟

من واقع تجربتي كمبرمج، تحولت اجتماعات مراجعة الحوادث التقنية من جلسات لوم واتهامات إلى بيئة آمنة للتعلم والنمو. في هذه المقالة، أشارككم كيف يمكن لـ...

21 مايو، 2026 قراءة المزيد
اختبارات الاداء والجودة

وداعاً لكابوس “هل كسرنا شيئاً؟”: كيف أنقذ اختبار التراجع البصري واجهاتنا الأمامية

كل تحديث للواجهة الأمامية كان بمثابة روليت روسية، مغامرة محفوفة بالمخاطر حتى اكتشفنا اختبار التراجع البصري. في هذه المقالة، أشارككم قصتنا كفريق تطوير وكيف حولنا...

21 مايو، 2026 قراءة المزيد
البودكاست