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 الموجودة لديك كطبقة تجميع بيانات. شاهد كيف يتفاعل فريقك معها، وقس بنفسك الفوائد التي ستحصل عليها. 🚀

أبو عمر

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

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

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

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

آخر المدونات

برمجة وقواعد بيانات

كان تحديث قاعدة البيانات يوقف خدماتنا: كيف أنقذتنا استراتيجيات الترحيل بدون توقف (Zero-Downtime Migration) من جحيم نافذة الصيانة؟

أشارككم قصة ليلة طويلة تعلمت فيها بالطريقة الصعبة أن "نافذة الصيانة" هي عدو للمستخدمين والشركات. نستكشف معاً استراتيجيات الترحيل بدون توقف (Zero-Downtime Migration) التي تحافظ...

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

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

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

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

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

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

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

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

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

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

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

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

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

كان الخوف من الفشل يشلّ فريقنا: كيف أنقذتنا ‘السلامة النفسية’ من جحيم الأفكار التي لم تولد قط؟

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

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