GraphQL: كيف أنقذنا من جحيم الـ Over-fetching والـ Under-fetching في تطبيقاتنا

قصة قهوة الصباح وتطبيق “الدكان”

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

الواجهة الرئيسية كانت تحتاج تعرض شوية معلومات من كل بستان زهرة: اسم المستخدم وصورته الشخصية في الأعلى، قائمة بأحدث 5 منتجات مع صورها المصغرة وأسعارها، وعدد الإشعارات غير المقروءة. فريق الواجهات الخلفية، جماعة شاطرين والله، عملوا لنا واجهات REST API “مرتبة” حسب رأيهم:

  • /api/users/me: للحصول على معلومات المستخدم.
  • /api/products?latest=5: للحصول على أحدث المنتجات.
  • /api/notifications/count: للحصول على عدد الإشعارات.

المشكلة؟ تطبيق الموبايل كان يضطر يرسل 3 طلبات مختلفة للشبكة (API Calls) بس عشان يرسم شاشة واحدة! هذا ما نسميه “التضور جوعًا للبيانات” أو Under-fetching. كل طلب له وقت استجابة، وتكاليف شبكة، وانتظار… والنتيجة؟ شاشة تظهر بالتقسيط، والمستخدم يمل ويترك التطبيق. ولما حكينا مع فريق الواجهات الخلفية، اقترحوا حلًا “عبقريًا”: عمل نقطة وصول (Endpoint) واحدة اسمها /api/home-screen ترجع كل شيء! وهنا وقعنا في الفخ الثاني.

نقطة الوصول الجديدة كانت ترجع “كوكتيل” بيانات ضخم. مثلًا، كائن المستخدم (User object) كان يرجع فيه كل تاريخه وعناوينه وسلة مشترياته، بينما نحن لا نريد سوى اسمه وصورته. والمنتجات كانت ترجع مع كل تفاصيلها ووصفها الطويل، ونحن لا نريد سوى الصورة والسعر. هذا هو جحيم “الغرق في البيانات” أو Over-fetching. التطبيق صار يحمّل بيانات بالهبل ما إلها لزوم، وهذا يستهلك باقة الإنترنت للمستخدم ويبطئ كل شيء.

كنت أجلس ذات صباح، أشرب فنجان قهوتي وأتصفح الإنترنت، وإذ بي أقرأ عن تقنية اسمها GraphQL. قرأت الجملة الأولى في موقعهم: “لغة استعلام لواجهة برمجة التطبيقات”. الفكرة بدت بسيطة وعبقرية: بدلًا من أن يقرر الخادم (Server) ما هي البيانات التي سيرسلها، يقوم العميل (Client) بطلب ما يحتاجه بالضبط، لا أكثر ولا أقل. وقتها لمعت عيناي وقلت: “هذا هو الحل يا جماعة!”.

ما هو الجحيم الذي كنا نعيشه؟ (مشاكل REST التقليدية)

قبل أن نغوص في حل GraphQL، دعونا نفصّل أكثر في المشاكل التي جعلت حياتنا صعبة مع REST APIs في سيناريوهات معينة.

h3: الغرق في البيانات (Over-fetching)

تخيل أنك تريد فقط معرفة أسماء المستخدمين في نظامك. في REST، قد يكون لديك نقطة وصول مثل GET /api/users. المشكلة أن هذه النقطة قد تكون مصممة لترجع كائن المستخدم الكامل:


// طلب REST: GET /api/users/1
// الاستجابة التي تصلك (أنت تحتاج الاسم فقط!)
{
  "id": 1,
  "name": "أبو عمر",
  "username": "abu_omar_dev",
  "email": "abu.omar@example.com",
  "address": {
    "street": "شارع يافا",
    "city": "القدس",
    "zipcode": "91000"
  },
  "phone": "059-XXXXXXX",
  "website": "abuomar.dev",
  "company": {
    "name": "برمجة بلا حدود",
    "catchPhrase": "نحول القهوة إلى كود"
  },
  "posts_count": 120,
  "followers_count": 5000
  // ... والمزيد من البيانات غير اللازمة
}

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

h3: التضور جوعًا للبيانات (Under-fetching) والطلبات المتتالية

هذه هي المشكلة المعاكسة، وهي أكثر شيوعًا في التطبيقات المعقدة. لنعد لمثال تطبيق “الدكان”. لعرض الصفحة الرئيسية، كنت تحتاج:

  1. طلب GET /api/posts للحصول على قائمة المقالات.
  2. تصلك قائمة المقالات، لكن كل مقال يحتوي على authorId فقط.
  3. الآن، لكل مقال في القائمة، عليك إرسال طلب جديد GET /api/users/{authorId} للحصول على اسم الكاتب.

إذا كانت الصفحة تعرض 10 مقالات، فهذا يعني أنك سترسل 1 (للمقالات) + 10 (للكتاب) = 11 طلبًا للشبكة! هذه المشكلة تعرف بـ “N+1 Query Problem” وهي قاتلة لأداء التطبيق.

وظهر النور في آخر النفق: مرحبًا GraphQL!

GraphQL ليست مكتبة، ولا إطار عمل، بل هي “مواصفة” أو “لغة استعلام” (Query Language) للـ APIs، تم تطويرها في فيسبوك عام 2012 وأصبحت مفتوحة المصدر في 2015. الفكرة الأساسية بسيطة بشكل يبعث على الدهشة: أعطِ العميل القدرة على طلب البيانات التي يحتاجها بالضبط.

بدلًا من وجود عشرات نقاط الوصول (Endpoints) الثابتة كما في REST، توفر GraphQL عادةً نقطة وصول واحدة فقط (مثل /graphql). العميل يرسل “استعلامًا” (Query) لهذه النقطة، يصف فيه شكل البيانات التي يريدها، والخادم يرد بنفس الشكل تمامًا.

h3: كيف يعمل هذا السحر؟ المكونات الأساسية

  1. Schema (المخطط): هو عقد ملزم بين العميل والخادم. يصف كل البيانات المتاحة في الـ API وأنواعها والعلاقات بينها. هو بمثابة “الكتالوج” الذي يتصفحه المطور ليعرف ما يمكنه طلبه.
  2. Query (الاستعلام): هو ما يرسله العميل لطلب البيانات. يشبه إلى حد كبير كائن JSON بدون قيم.
  3. Mutation (التعديل): تشبه الـ Query، لكنها تستخدم لتعديل البيانات (إنشاء، تحديث، حذف).
  4. Resolvers (المُحلِّلات): هي “العضلات” في الخادم. لكل حقل في المخطط، هناك دالة (resolver function) مسؤولة عن جلب بيانات هذا الحقل من قاعدة البيانات أو من أي مصدر آخر.

كلام نظري ما بطعمي خبز: خلينا نشوف الكود

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

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

كما ذكرنا، كنا سنحتاج لعدة طلبات:


// الطلب الأول
GET /api/posts

// الطلب الثاني (بعد استلام رد الطلب الأول)
GET /api/users/101 // لكاتب المقال الأول

// الطلب الثالث
GET /api/users/102 // لكاتب المقال الثاني

// وهكذا...

h3: طريقة الشغل النظيف (GraphQL)

الآن، مع GraphQL، يرسل العميل طلبًا واحدًا فقط يصف كل ما يحتاجه:


# هذا هو استعلام GraphQL
query GetPostsAndAuthors {
  posts {
    title
    publishedDate
    author {
      name
      avatarUrl
    }
  }
}

والخادم، بعد تلقي هذا الاستعلام، سيفهمه ويقوم بتجميع البيانات المطلوبة ويرسل استجابة JSON تبدو مطابقة تمامًا لشكل الطلب:


// هذه هي الاستجابة من الخادم (في طلب واحد!)
{
  "data": {
    "posts": [
      {
        "title": "مقالتي الأولى عن GraphQL",
        "publishedDate": "2023-10-27",
        "author": {
          "name": "أبو عمر",
          "avatarUrl": "https://example.com/abu_omar.jpg"
        }
      },
      {
        "title": "لماذا يجب أن تتعلم TypeScript",
        "publishedDate": "2023-10-26",
        "author": {
          "name": "مطور آخر",
          "avatarUrl": "https://example.com/another_dev.jpg"
        }
      }
    ]
  }
}

لاحظ الجمال هنا: طلب واحد، استجابة واحدة، لا بيانات زائدة (no over-fetching)، ولا حاجة لطلبات إضافية (no under-fetching). العميل أخذ بالضبط ما طلبه. شغل من الآخر!

نصائح من “الختيار”: متى تستخدم GraphQL؟

بعد سنوات من العمل مع هذه التقنية، تعلمت أنها ليست “الحل السحري” لكل شيء. “ما في إشي بحل كل المشاكل”. إليك بعض النصائح من خبرتي العملية:

  • التطبيقات المعقدة أولًا: إذا كان لديك تطبيق (خاصة موبايل أو Single Page Application) يحتاج بيانات من مصادر متعددة في شاشة واحدة، فـ GraphQL هو صديقك الصدوق.
  • تعدد العملاء: عندما يكون لديك عدة واجهات (ويب، iOS، أندرويد، ساعة ذكية) ولكل منها متطلبات بيانات مختلفة، تتيح لك GraphQL خدمة الجميع من خلال API واحد مرن دون الحاجة لتخصيص نقاط وصول لكل عميل.
  • لا تخف من منحنى التعلم: نعم، إعداد خادم GraphQL (المخطط والمحللات) يتطلب جهدًا في البداية أكبر من إعداد نقطة وصول REST بسيطة. لكن هذا الجهد يؤتي ثماره على المدى الطويل في سهولة الصيانة والتطوير.
  • متى لا تستخدمها؟: إذا كان تطبيقك بسيطًا جدًا، أو لديك خدمة مصغرة (microservice) تؤدي وظيفة واحدة فقط (مثل خدمة إرسال الإيميلات)، فقد يكون استخدام REST API تقليدي أبسط وأسرع في التنفيذ. لا تعقّد الأمور بدون داعٍ.

نصيحة إضافية: GraphQL رائعة في “تغليف” الواجهات القديمة. يمكنك بناء واجهة GraphQL جديدة أمام واجهات REST القديمة لديك، مما يمنحك كل مزايا GraphQL دون الحاجة لإعادة كتابة كل شيء من الصفر.

الخلاصة: هل نرمي REST في البحر؟

بالتأكيد لا! REST لم تمت ولن تموت قريبًا. هي تقنية قوية، بسيطة، ومناسبة جدًا لآلاف السيناريوهات. لكن GraphQL جاءت لتقدم حلًا أنيقًا لمجموعة من المشاكل التي كانت تؤرقنا كمطورين، خاصة في عالم التطبيقات الحديثة التي تزداد تعقيدًا يومًا بعد يوم.

الخلاصة يا جماعة، أن تكون في جعبتك الأداتان (REST و GraphQL) وتعرف متى تستخدم كل منهما هو ما يجعلك مطورًا محترفًا. لا تكن متعصبًا لتقنية واحدة، بل افهم المشكلة التي بين يديك واختر لها السلاح المناسب.

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

أبو عمر

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

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

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

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

آخر المدونات

الشبكات والـ APIs

كانت خوادمنا تستجدي التحديثات: كيف أنقذتنا ‘خطاطيف الويب’ (Webhooks) من جحيم الاستقصاء المستمر (Polling)؟

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

17 مايو، 2026 قراءة المزيد
الحوسبة السحابية

كانت بنيتنا التحتية قصراً من رمال: كيف أنقذتنا “البنية التحتية ككود” (IaC) من جحيم البيئات المتضاربة؟

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

17 مايو، 2026 قراءة المزيد
التوظيف وبناء الهوية التقنية

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

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

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

كانت قاعدة بياناتنا تتوسل الرحمة: كيف أنقذنا التخزين المؤقت (Caching) من جحيم الاستعلامات البطيئة

قصة حقيقية من واقع العمل عن كيفية انهيار نظامنا تحت ضغط الاستعلامات المتكررة، وكيف كان التخزين المؤقت (Caching) هو طوق النجاة. مقالة عملية للمطورين تشرح...

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

كان التحقق من هوية عملائنا يستغرق أياماً: كيف أنقذنا الذكاء الاصطناعي (eKYC) من جحيم الإجراءات اليدوية؟

بصفتي مبرمجاً فلسطينياً، سأروي لكم حكايتنا مع كابوس التحقق اليدوي من هوية العملاء (KYC) وكيف كانت رحلة الانتقال إلى التحقق الإلكتروني (eKYC) باستخدام الذكاء الاصطناعي...

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

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

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

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

كانت فرقنا صامتة أمام الأخطاء: كيف أنقذتنا ‘السلامة النفسية’ من جحيم ثقافة اللوم؟

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

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