واجهاتي كانت تغرق المستخدمين ببيانات لا يحتاجونها: كيف أنقذني GraphQL من جحيم الـ Over-fetching؟

السلام عليكم يا جماعة الخير، معكم أخوكم أبو عمر.

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

لكن المصيبة بانت لما بلشنا نجرّب التطبيق على شبكات الجوال الحقيقية (3G وقتها). فتح الصفحة الرئيسية كان يأخذ ثوانٍ طويلة، والتنقل بين الصفحات كان كابوساً. المستخدمون التجريبيون اشتكوا من بطء التطبيق واستهلاكه الكبير لباقة الإنترنت. شعرت بإحباط شديد، كيف لتطبيق بسيط أن يكون بهذا البطء؟

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

هذه القصة كانت نقطة تحول في مسيرتي المهنية، واليوم سأشارككم كيف أنقذتني تقنية GraphQL من هذا الجحيم.

ما هو الـ Over-fetching؟ تشريح المشكلة

ببساطة شديدة، الـ Over-fetching يعني “جلب بيانات أكثر من اللازم”. عندما يقوم تطبيق العميل (المتصفح أو تطبيق الجوال) بطلب بيانات من الخادم عبر واجهة برمجية (API)، ويقوم الخادم بإرسال حزمة بيانات أكبر بكثير مما يحتاجه العميل لعرض الواجهة الحالية.

دعونا نأخذ مثالاً أوضح. تخيل أن لديك مدونة، وتحتاج إلى عرض قائمة بآخر 10 مقالات في الصفحة الرئيسية. كل ما تحتاجه في هذه القائمة هو:

  • عنوان المقال (title)
  • اسم الكاتب (authorName)
  • صورة المقال المصغرة (thumbnailUrl)

في عالم REST API التقليدي، من المحتمل أن يكون لديك نقطة نهاية (endpoint) مثل GET /api/posts. عند استدعاء هذه النقطة، قد يبدو الرد الذي يصلك هكذا لكل مقال في القائمة:


{
  "id": 123,
  "title": "عنوان المقال الأول",
  "content": "محتوى المقال كاملاً... نص طويل جداً جداً...",
  "author": {
    "id": 45,
    "name": "أبو عمر",
    "bio": "مبرمج ومطور برمجيات فلسطيني...",
    "social_links": {
      "twitter": "...",
      "linkedin": "..."
    }
  },
  "tags": ["تطوير", "برمجة", "API"],
  "comments": [
    { "user": "أحمد", "comment": "مقال رائع!" },
    { "user": "سارة", "comment": "شكراً على المعلومات" },
    // ... وقد يكون هناك 100 تعليق آخر
  ],
  "createdAt": "2023-10-27T10:00:00Z",
  "updatedAt": "2023-10-27T12:30:00Z",
  "thumbnailUrl": "url/to/image.jpg"
}

لاحظت المشكلة؟ أنت تحتاج فقط 3 حقول، ولكن الخادم أرسل لك 8 حقول رئيسية، بعضها يحتوي على كائنات متداخلة وقوائم طويلة (مثل التعليقات). الآن اضرب حجم هذه البيانات الزائدة في 10 مقالات. النتيجة هي طلب شبكة بطيء يستهلك بيانات ثمينة، خاصة على أجهزة الجوال.

الطريقة التقليدية (REST) ومحدوديتها

بالتأكيد، هناك حلول لهذه المشكلة في عالم REST. لكنها، من وجهة نظري، أشبه بوضع “لصقات جروح” على مشكلة نظامية.

الحل الأول: إنشاء نقاط نهاية متعددة

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

  • /api/posts: لإرجاع البيانات الكاملة للمقال.
  • /api/posts/summary: لإرجاع ملخص بسيط للمقالات لعرضه في القائمة.

هذا الحل يعمل في البداية، ولكنه يتحول إلى كابوس مع نمو التطبيق. ستجد نفسك مع عشرات، بل مئات، من نقاط النهاية. ماذا لو أرادت واجهة أخرى عرض العنوان والكاتب فقط؟ هل ننشئ /api/posts/titles؟ هذا يجعل صيانة الـ API وإدارتها أمراً معقداً جداً.

الحل الثاني: استخدام معاملات الاستعلام (Query Parameters)

حل آخر هو السماح للعميل بتحديد الحقول التي يريدها عبر معاملات الاستعلام، هكذا:


GET /api/posts?fields=title,authorName,thumbnailUrl

هذا أفضل بكثير! لكنه ليس معياراً قياسياً في REST، ويتطلب تنفيذاً مخصصاً على الخادم لكل نقطة نهاية. كما أنه يصبح معقداً جداً عند التعامل مع البيانات المتداخلة (Nested Data). كيف ستطلب اسم الكاتب فقط دون بقية بياناته؟ ربما هكذا؟ fields=title,author.name,thumbnailUrl. الأمر يبدأ بالخروج عن السيطرة بسرعة.

المنقذ GraphQL: كيف غيرت قواعد اللعبة؟

هنا يأتي دور GraphQL، وهي ليست مكتبة أو إطار عمل، بل هي **لغة استعلام للـ APIs** (Query Language for APIs) تم تطويرها بواسطة فيسبوك. الفكرة عبقرية وبسيطة في آن واحد.

المبدأ بسيط: أنت تطلب، الخادم يجيب على قد الطلب

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

لنعد لمثال المدونة. بدلاً من استدعاء /api/posts، سيرسل العميل طلباً (عادةً POST) إلى نقطة نهاية GraphQL واحدة (مثلاً /graphql) مع الاستعلام التالي:


query GetPostsSummary {
  posts(limit: 10) {
    title
    author {
      name
    }
    thumbnailUrl
  }
}

وستكون الاستجابة من الخادم مطابقة تماماً لهذا الشكل، لا زيادة ولا نقصان:


{
  "data": {
    "posts": [
      {
        "title": "عنوان المقال الأول",
        "author": {
          "name": "أبو عمر"
        },
        "thumbnailUrl": "url/to/image.jpg"
      },
      // ... 9 مقالات أخرى بنفس البنية
    ]
  }
}

لاحظ الجمال هنا! طلبنا فقط اسم الكاتب (author.name) وليس كل بياناته، وهذا بالضبط ما حصلنا عليه. لا يوجد أي Over-fetching. إذا احتاجت شاشة أخرى في التطبيق لعرض التعليقات، يمكنها ببساطة إضافة comments إلى الاستعلام.

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

منذ أن تبنيت GraphQL في مشاريعي، لمست فوائد عملية غيرت طريقة عملي وفريقي بالكامل.

1. نهاية الـ Over-fetching والـ Under-fetching

تحدثنا مطولاً عن الـ Over-fetching. لكن GraphQL تحل أيضاً مشكلة معاكسة اسمها Under-fetching. هذه المشكلة تحدث عندما لا توفر نقطة النهاية كل البيانات المطلوبة، مما يضطر العميل إلى إرسال طلبات متعددة للحصول على كل ما يحتاجه. مثلاً، طلب /posts ثم لكل مقال، طلب /authors/{authorId}. هذا يسبب ما يسمى “N+1 problem”.

مع GraphQL، يمكنك جلب كل البيانات المترابطة التي تحتاجها في طلب واحد فقط، مهما كانت معقدة.

2. نقطة نهاية واحدة (Single Endpoint)

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

3. توثيق ذاتي (Self-documenting)

نصيحة من أبو عمر: من أكبر المشاكل التي واجهتها مع REST APIs هي أن التوثيق (Documentation) دائماً ما يكون قديماً أو غير مكتمل. كم مرة قرأت توثيقاً يقول شيئاً، والـ API الفعلية تفعل شيئاً آخر؟

GraphQL مبنية على نظام أنواع صارم (Strongly Typed Schema). هذا الـ Schema يصف كل البيانات المتاحة في الـ API وكيفية طلبها. والأجمل من ذلك، أن هذا الـ Schema يمكن استكشافه برمجياً. أدوات مثل GraphiQL أو GraphQL Playground توفر لك واجهة تفاعلية لاستكشاف الـ API بالكامل، وقراءة التوثيق، وتجربة الاستعلامات مباشرةً. صار التوثيق جزءاً من الكود، مش ملف PDF بننساه.

4. تطوير أسرع للواجهات الأمامية

هذه كانت أكبر فائدة لفريقي. لم يعد مطورو الواجهات الأمامية (Frontend) ينتظرون فريق الواجهات الخلفية (Backend) لإنشاء أو تعديل نقطة نهاية. إذا احتاجوا حقلاً جديداً في واجهة ما، كل ما عليهم فعله هو إضافته إلى استعلام GraphQL الخاص بهم. هذا يمنحهم استقلالية وسرعة هائلة في التطوير.

نصائح أبو عمر: متى تستخدم GraphQL؟ وهل هو بديل كامل لـ REST؟

GraphQL ليست “الحل السحري” لكل المشاكل، ومن المهم أن نعرف متى نستخدمها.

  • استخدم GraphQL عندما:
    • تطبيقاتك لديها عملاء متنوعون (ويب، جوال، ساعة ذكية) ولكل منهم احتياجات بيانات مختلفة.
    • واجهاتك معقدة وتحتاج إلى بيانات من مصادر متعددة في شاشة واحدة (مثل لوحات التحكم).
    • سرعة الشبكة واستهلاك البيانات عامل حاسم (خصوصاً في تطبيقات الجوال).
    • تريد تمكين فرق الواجهات الأمامية ومنحهم استقلالية أكبر.
  • قد يكون REST خياراً أفضل عندما:
    • الـ API بسيطة جداً وتتعامل مع موارد محددة وغير متغيرة (مثل API داخلية بين خدمتين مصغرتين).
    • الاعتماد على آليات التخزين المؤقت (Caching) الخاصة بـ HTTP (مثل GET requests) هو أولوية قصوى. GraphQL عادةً ما تستخدم طلبات POST، مما يجعل التخزين المؤقت على مستوى HTTP أكثر تعقيداً.

والنصيحة الأهم: GraphQL و REST يمكن أن يتعايشا بسلام! يمكنك بناء واجهة GraphQL (Gateway) تجلس أمام خدمات REST المصغرة (Microservices) الموجودة لديك. تقوم هذه الواجهة بتجميع البيانات من خدمات REST المختلفة وتقديمها للعميل عبر GraphQL. هذا نمط قوي جداً في الأنظمة الكبيرة.

الخلاصة: هل تستحق GraphQL كل هذا العناء؟

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

يا جماعة الخير، التكنولوجيا أداة. والمهم هو أن نعرف أي أداة نستخدم ومتى نستخدمها. بالنسبة لي، GraphQL كانت المطرقة المناسبة تماماً للمسمار الذي كان “معذبني” لسنوات طويلة وهو الـ Over-fetching. لقد حررتني من قيود الـ API التقليدية وفتحت أمامي آفاقاً جديدة لبناء تطبيقات أسرع وأكثر كفاءة. 🚀

أتمنى أن تكون هذه التجربة مفيدة لكم. وإذا كان لديكم أي سؤال، فأنا جاهز في التعليقات. الله يوفقكم جميعاً.

أبو عمر

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

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

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

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

آخر المدونات

تسويق رقمي

محتواي كان شبحاً في محركات البحث: كيف أنقذتني البيانات المنظمة (Structured Data) من جحيم الغموض الرقمي؟

أشارككم قصتي مع موقعي الذي كان خفياً تماماً في جوجل، وكيف استطعت إخراجه للنور باستخدام البيانات المنظمة (Structured Data) و Schema.org. هذه ليست مجرد مقالة...

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

خوادمي كانت تلتهم ميزانيتي: كيف أنقذتني الحوسبة “بدون خوادم” (Serverless) من فواتير السحابة المتضخمة؟

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

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

سيرتي الذاتية كانت مقبرة للمهارات: كيف أنقذني ‘منهج الإنجاز’ من الرفض التلقائي؟

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

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

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

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

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

تطبيقي كان جزيرة معزولة: كيف أنقذتني واجهات برمجة التطبيقات المصرفية المفتوحة (Open Banking APIs)؟

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

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

تغطية اختباراتي 100% كانت مجرد وهم: كيف كشف لي ‘اختبار الطفرات’ (Mutation Testing) عن نقاط الضعف الخفية في جودة الكود؟

كنت أظن أن وصول تغطية الاختبارات (Test Coverage) إلى 100% هو قمة جودة البرمجيات، حتى اكتشفت "اختبار الطفرات" (Mutation Testing). في هذه المقالة، أشارككم قصتي...

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