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

يا جماعة الخير، السلام عليكم ورحمة الله.

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

قعدنا كفريق، حطينا كاسة شاي بنعنع، وفتحنا الـ Network Inspector. وهنا كانت الصدمة. عشان نعرض قائمة بسيطة من المقالات، فيها بس العنوان واسم الكاتب، كانت الـ REST API تبعتنا بترجّع لكل مقال “جريدة” كاملة: محتوى المقال كله، قائمة بكل التعليقات، أسماء كل اللي عملوا “لايك”، وتاريخ التعديل، وتفاصيل ما إلها أول من آخر. التطبيق المسكين كان بيغرق في بحر من البيانات اللي ما بحتاجها أصلاً! هاي المشكلة اللي بنسميها Over-fetching.

وعلى الجهة الثانية، في صفحة بروفايل المستخدم، كنا بدنا نعرض معلومات المستخدم ومنشوراته الأخيرة. فاضطرينا نعمل طلب API عشان نجيب معلومات المستخدم، وبعدين طلب ثاني عشان نجيب قائمة منشوراته، ومرات طلب ثالث ورابع لكل منشور عشان نجيب عدد التعليقات عليه. سلسلة من الطلبات ورا بعضها بتخلي التطبيق يستنى ويستنى… وهاي المشكلة بنسميها Under-fetching.

كنا عايشين في جحيم تقني، بين مطرقة البيانات الزائدة وسندان الطلبات المتعددة. لحد ما واحد من الشباب حكى كلمة غيّرت كل شيء: “يا جماعة، شو رأيكم نجرّب GraphQL؟”.

ما هو الجحيم الذي كنا نعيش فيه؟ (مشاكل الـ Over-fetching والـ Under-fetching)

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

الـ Over-fetching: لما التطبيق يغرق بالبيانات

تخيل أنك ذهبت إلى مطعم وطلبت كوب ماء، فجاء النادل وأحضر لك كل ما في المطبخ: أطباق، وحلويات، ومشروبات، ووضعها على طاولتك. هذا بالضبط ما يفعله الـ Over-fetching.

في عالم الـ APIs، هذا يعني أن العميل (تطبيق الويب أو الموبايل) يطلب معلومة صغيرة، لكن الخادم (Server) يرسل له حزمة بيانات ضخمة تحتوي على كل شيء يتعلق بهذا الطلب.

مثال عملي (REST API):

لدينا نقطة نهاية (Endpoint) لجلب المقالات GET /api/articles/1. نحن في الواجهة الأمامية نريد فقط عرض العنوان والمؤلف، لكن الـ API يرجع لنا هذا الـ JSON الضخم:


{
  "id": 1,
  "title": "مقدمة في الذكاء الاصطناعي",
  "content": "هنا يوجد محتوى المقال كاملاً بالآلاف من الكلمات...",
  "author": {
    "id": 101,
    "name": "أبو عمر",
    "bio": "مبرمج فلسطيني يحب الشاي والبرمجة...",
    "avatar_url": "https://example.com/avatar.jpg"
  },
  "tags": ["AI", "Programming", "Tech"],
  "comments": [
    { "user": "أحمد", "comment": "مقال رائع!" },
    { "user": "فاطمة", "comment": "شكراً على المعلومات القيمة." }
    // ... و 50 تعليق آخر
  ],
  "published_at": "2023-10-27T10:00:00Z",
  "updated_at": "2023-10-27T12:30:00Z"
}

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

الـ Under-fetching: رحلة الألف ميل تبدأ بـ… 10 طلبات API!

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

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

مثال عملي (REST API):

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

  1. GET /api/users/101 للحصول على معلومات المستخدم.
  2. GET /api/users/101/posts للحصول على قائمة بمعرفات (IDs) منشوراته.
  3. GET /api/posts/1 للحصول على تفاصيل المنشور الأول.
  4. GET /api/posts/2 للحصول على تفاصيل المنشور الثاني.
  5. GET /api/posts/3 للحصول على تفاصيل المنشور الثالث.

هذا “شلال” الطلبات (Request Waterfall) كارثي للأداء، فكل طلب له وقت استجابة خاص به، والمجموع الكلي هو وقت انتظار طويل ومزعج للمستخدم.

المنقذ وصل: تقديم GraphQL

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

نصيحة من أبو عمر: لا تفكر في GraphQL كبديل لقاعدة بياناتك (مثل MySQL أو MongoDB). فكر فيها كطبقة ذكية تجلس بين العميل (تطبيقك) والخادم، تتيح للعميل أن “يصف” البيانات التي يريدها بدقة، وتقوم هي بتجميعها له من مصادرك المختلفة.

كيف تعمل GraphQL؟ الطلب على قد الحاجة

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

هذا يعتمد على ثلاثة مفاهيم أساسية:

  • Schema (المخطط): هو العقد بين العميل والخادم. يتم تعريفه في الخادم، ويصف كل أنواع البيانات المتاحة، الحقول داخل كل نوع، والعلاقات بينها. هو بمثابة “قائمة الطعام” الكاملة التي يمكن للعميل أن يطلب منها.
  • Query (الاستعلام): هو الطلب الذي يرسله العميل. يكتبه العميل ليحدد الحقول التي يريدها من الـ Schema.
  • Resolver (المُحَلِّل): هي دوال (Functions) في الخادم. كل حقل في الـ Schema له Resolver خاص به. وظيفة الـ Resolver هي جلب البيانات لهذا الحقل (من قاعدة بيانات، من API آخر، من ملف، إلخ).

GraphQL في الميدان: مقارنة عملية مع REST

دعونا نعد إلى مشاكلنا الأصلية ونرى كيف حلتها GraphQL.

مثال 1: حل مشكلة الـ Over-fetching (عرض قائمة المقالات)

بدلاً من استدعاء GET /api/articles والحصول على بيانات لا نريدها، نرسل الآن طلب POST إلى /graphql مع الاستعلام التالي:


query GetArticleTitles {
  articles {
    id
    title
    author {
      name
    }
  }
}

والاستجابة التي سنحصل عليها ستكون نظيفة ودقيقة ومطابقة تماماً لما طلبناه:


{
  "data": {
    "articles": [
      {
        "id": "1",
        "title": "مقدمة في الذكاء الاصطناعي",
        "author": {
          "name": "أبو عمر"
        }
      },
      {
        "id": "2",
        "title": "أساسيات تطوير الويب",
        "author": {
          "name": "أبو عمر"
        }
      }
    ]
  }
}

لاحظ كيف أن العميل هو من تحكم بشكل الاستجابة. لا يوجد بيانات زائدة، لا يوجد إهدار في الشبكة. مشكلة الـ Over-fetching اختفت!

مثال 2: حل مشكلة الـ Under-fetching (عرض صفحة المستخدم)

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


query GetUserProfile {
  user(id: "101") {
    id
    name
    bio
    posts(limit: 3) {
      id
      title
      likesCount
    }
  }
}

والخادم سيقوم بتجميع كل هذه البيانات ويرسلها في استجابة واحدة متكاملة:


{
  "data": {
    "user": {
      "id": "101",
      "name": "أبو عمر",
      "bio": "مبرمج فلسطيني يحب الشاي والبرمجة...",
      "posts": [
        {
          "id": "1",
          "title": "مقدمة في الذكاء الاصطناعي",
          "likesCount": 150
        },
        {
          "id": "5",
          "title": "لماذا GraphQL رائعة؟",
          "likesCount": 230
        },
        {
          "id": "8",
          "title": "نصائح للعمل عن بعد",
          "likesCount": 95
        }
      ]
    }
  }
}

بطلب واحد، حصلنا على كل ما نحتاجه لعرض الصفحة. مشكلة الـ Under-fetching تبخرت!

نصائح من أبو عمر: متى تستخدم GraphQL (ومتى لا تستخدمها)

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

متى تكون GraphQL خياراً ممتازاً؟

  • تطبيقات الموبايل: حساسية تطبيقات الموبايل لاستهلاك البيانات والبطارية تجعل GraphQL الخيار الأمثل لتقليل حجم البيانات المنقولة وعدد الطلبات.
  • الواجهات الأمامية المعقدة (SPAs): عندما يكون لديك واجهة أمامية مبنية بأطر عمل مثل React أو Vue أو Angular، وتحتاج إلى عرض بيانات متداخلة من مصادر مختلفة في شاشة واحدة، فإن GraphQL تبسط الأمر بشكل كبير.
  • فرق عمل متعددة: عندما يكون لديك فريق للواجهة الأمامية، وفريق للموبايل، وفريق للواجهة الخلفية، يعمل الـ Schema في GraphQL كـ “عقد” أو “وثيقة” واضحة وموحدة للجميع، مما يقلل من سوء التفاهم ويسرّع التطوير.

متى قد لا تكون GraphQL الخيار الأفضل؟

  • التطبيقات البسيطة جداً: إذا كان تطبيقك مجرد واجهة CRUD بسيطة (إنشاء، قراءة، تحديث، حذف) لعدد قليل من الموارد، فإن REST API التقليدية قد تكون أسرع في الإعداد وأبسط في الإدارة.
  • واجهات API العامة المفتوحة: بناء API عامة باستخدام GraphQL يتطلب تفكيراً إضافياً في مسائل مثل تحديد معدل الطلبات (Rate Limiting) وتكاليف الاستعلامات المعقدة، والتي قد تكون أسهل في REST.
  • عندما تحتاج إلى بساطة الـ Caching في HTTP: الـ Caching في REST API مباشر جداً بالاعتماد على URL والـ HTTP Verbs. في GraphQL، بما أن كل الطلبات تذهب لنقطة نهاية واحدة (/graphql) عبر POST، فإن الـ Caching يحتاج إلى استراتيجيات أكثر تعقيداً على مستوى العميل (مثل Apollo Client) أو الخادم.

الخلاصة: هل نودّع REST للأبد؟

لا، بالطبع لا. REST ما زالت تقنية عظيمة ومناسبة جداً لآلاف الحالات. الفكرة ليست في استبدال تقنية بأخرى، بل في فهم نقاط القوة والضعف لكل منهما واختيار الأنسب للمهمة التي بين يديك.

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

نصيحتي الأخيرة لك: لا تخف من التجربة. إذا كنت تعاني من مشاكل الـ Over/Under-fetching في مشاريعك، ابدأ بتجربة GraphQL على نطاق صغير. يمكنك بناء خادم GraphQL يعمل “فوق” REST APIs الموجودة لديك كطبقة تجميع بيانات. شاهد كيف يتفاعل فريقك معها، وقس بنفسك الفوائد التي ستحصل عليها. 🚀

أبو عمر

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

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

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

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

آخر المدونات

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

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

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

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

كنت أرتبك في المقابلات السلوكية: كيف أنقذني أسلوب STAR من جحيم الإجابات العشوائية؟

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

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

كان فشل خدمة واحدة ينسف النظام بأكمله: كيف أنقذنا نمط ‘قاطع الدائرة’ (Circuit Breaker) من جحيم الفشل المتتالي؟

أشارككم قصة حقيقية من قلب المعركة البرمجية، كيف كاد نظامنا ينهار بسبب فشل خدمة صغيرة، وكيف كان نمط "قاطع الدائرة" (Circuit Breaker) هو طوق النجاة...

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

شبكة الخدمة (Service Mesh): طوق النجاة الذي أنقذنا من جحيم تتبع الأخطاء في الخدمات المصغرة

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

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