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

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

تواصلت مع فريق الباك-إند (Backend) وطلبت منهم واجهة برمجية (API Endpoint) تجيبلي بيانات الموظفين. الشباب ما قصّروا، وأعطوني endpoint معمول بـ REST، شكله زي هيك: /api/employees/{id}. لما جربت الـ endpoint لأول مرة، انصدمت! عشان أجيب اسم موظف واحد وصورته، الـ API كان يرجعلي “جريدة” كاملة من البيانات: تاريخ ميلاده، عنوان سكنه بالتفصيل، كل تقارير الأداء اللي أخذها من يوم ما توظف، قائمة بأفراد عائلته المسجلين في التأمين الصحي، وحتى فصيلة دمه! يا زلمة، حسيت حالي بطلب صحن حمص، بيجيني معاه خروف محشي!

المشكلة إنه عشان أعرض قائمة من 10 موظفين، كنت مضطر أعمل 10 طلبات (requests)، وكل طلب يرجعلي جبل من البيانات أنا مش بحاجتها بالمرة. النتيجة؟ التطبيق صار بطيء جداً، خصوصاً على اتصالات الإنترنت الضعيفة، والبطارية بتخلص بسرعة، وتجربة المستخدم كانت في الحضيض. وقتها عرفت إني وقعت في فخ اسمه “Over-fetching”، وهو الكابوس اللي راح أحكيلكم كيف تخلصت منه بفضل تقنية عملت نقلة نوعية في شغلي: GraphQL.

ما هو كابوس الـ Over-fetching؟

ببساطة، الـ Over-fetching يعني إن الواجهة البرمجية (API) بترسل بيانات أكثر بكثير من اللي بيحتاجها العميل (Client)، سواء كان تطبيق موبايل، موقع ويب، أو أي نظام آخر. تخيل أنك تريد فقط معرفة عنوان كتاب من مكتبة ضخمة، لكن أمين المكتبة يصر على أن يعطيك الكتاب بأكمله مع سيرة ذاتية للمؤلف وقائمة بكل الكتب الأخرى التي كتبها. هذا بالضبط ما يحدث في عالم البرمجة، وهو مشكلة أكبر مما تتصور.

لماذا يعتبر الـ Over-fetching مشكلة حقيقية؟

  • استهلاك الباندويث (Bandwidth): نقل بيانات غير ضرورية يستهلك من باقة الإنترنت للمستخدم ويزيد الضغط على خوادمك.
  • بطء الأداء: كلما زاد حجم البيانات، زاد الوقت اللازم لنقلها ومعالجتها على جهاز العميل، مما يجعل التطبيق بطيئاً وغير مستجيب.
  • زيادة التكلفة: على مستوى الخوادم، نقل كميات هائلة من البيانات يعني تكاليف أعلى في استهلاك الشبكة وقوة المعالجة.
  • تجربة مستخدم سيئة: من الآخر، لا أحد يحب تطبيقاً بطيئاً. البطء هو أول سبب يجعل المستخدمين يحذفون تطبيقك.

الطريقة التقليدية: جحيم الـ REST APIs

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

في قصتي، كان الـ Endpoint /api/employees/123 يرجع دائماً شيئاً كهذا:


{
  "id": 123,
  "fullName": "سعيد الفلسطيني",
  "jobTitle": "مهندس برمجيات أول",
  "email": "saeed@example.com",
  "phoneNumber": "+970...",
  "address": {
    "street": "شارع عمر المختار",
    "city": "غزة",
    "country": "فلسطين"
  },
  "profilePictureUrl": "https://example.com/images/saeed.jpg",
  "performanceReviews": [
    { "year": 2022, "rating": 4.8, "notes": "أداء استثنائي..." },
    { "year": 2021, "rating": 4.5, "notes": "تطور ملحوظ..." }
    // ... عشرات المراجعات الأخرى
  ],
  "emergencyContacts": [
    // ... قائمة بجهات الاتصال للطوارئ
  ]
}

أنا كل اللي كنت محتاجه من كل هذا “الجبل” هو حقلين فقط: fullName و profilePictureUrl. كل الباقي كان عبئاً لا أكثر.

محاولات الترقيع في عالم REST

طبعاً، المبرمجون أذكياء وحاولوا إيجاد حلول لهذه المشكلة ضمن REST نفسها:

  1. إنشاء Endpoints مخصصة: مثل /api/employees/123/summary. هذا يحل المشكلة لواجهة واحدة، لكن مع نمو التطبيق، ينتهي بك الأمر مع مئات الـ Endpoints المختلفة، ويصبح الحفاظ عليها وصيانتها كابوساً بحد ذاته.
  2. استخدام Query Parameters: مثل /api/employees/123?fields=fullName,profilePictureUrl. هذا حل أفضل بكثير، ولكنه غير قياسي. كل فريق يطبقه بطريقته الخاصة، ويحتاج إلى برمجة منطق خاص على الخادم لتحليله، وقد يصبح معقداً جداً مع البيانات المتشعبة.

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

المنقذ GraphQL: اطلب ما تحتاجه بالضبط، وبلا وجعة راس!

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

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

مثال عملي: من REST إلى GraphQL

لحل مشكلتي في التطبيق، لو كان الباك-إند يستخدم GraphQL، لكنت أرسلت الاستعلام التالي:


query GetEmployeeNameAndPicture {
  employee(id: 123) {
    fullName
    profilePictureUrl
  }
}

والخادم كان سيرد عليّ بهذه الإجابة الجميلة والبسيطة:


{
  "data": {
    "employee": {
      "fullName": "سعيد الفلسطيني",
      "profilePictureUrl": "https://example.com/images/saeed.jpg"
    }
  }
}

لاحظ الجمال! طلبت حقلين، حصلت على حقلين. لا بيانات ضائعة، لا استهلاك زائد للشبكة، أداء سريع، وتطبيق “إشي مرتب”. هذا هو الفرق الجوهري الذي يحل مشكلة الـ Over-fetching من جذورها.

ليس فقط Over-fetching، بل Under-fetching أيضاً!

هناك مشكلة أخرى شائعة في REST اسمها Under-fetching. وهي عكس المشكلة الأولى، وتعني أن الـ Endpoint الواحد لا يعطيك كل البيانات التي تحتاجها، فتضطر لعمل عدة طلبات متتالية. مثلاً، تريد عرض اسم المستخدم وآخر 3 تدوينات له. في REST، قد تحتاج لطلبين:

  1. GET /api/users/{id} للحصول على معلومات المستخدم.
  2. GET /api/users/{id}/posts?limit=3 للحصول على تدويناته.

أما في GraphQL، فيمكنك طلب كل هذا في استعلام واحد فقط:


query GetUserWithPosts {
  user(id: 456) {
    name
    posts(last: 3) {
      title
      createdAt
    }
  }
}

بهذا، حلت GraphQL مشكلتين رئيسيتين بضربة واحدة: طلب بيانات أكثر من اللازم (Over-fetching) والحاجة لطلبات متعددة لجلب البيانات (Under-fetching).

نصائح من مطبخ أبو عمر 🤓

بعد سنوات من العمل مع GraphQL، تعلمت بعض الدروس التي أحب أن أشاركها معكم:

ابدأ بالـ Schema أولاً (Schema-First Design)

قبل كتابة أي كود للخادم، قم بتصميم الـ “Schema” الخاصة بالـ API. الـ Schema هي العقد بينك وبين مطوري الواجهات الأمامية (Frontend). هي التي تحدد أنواع البيانات المتاحة وكيفية الاستعلام عنها. هذا التنظيم يمنع الكثير من المشاكل المستقبلية.

الأمان، ثم الأمان، ثم الأمان

لأن GraphQL مرنة جداً، قد يحاول أحدهم إرسال استعلام معقد جداً يستهلك كل موارد الخادم (يُعرف بـ “Denial of Service attack”). تأكد من تطبيق آليات حماية مثل: تحديد أقصى عمق للاستعلام (Query Depth Limiting)، تحديد تعقيد الاستعلام (Query Complexity)، وبالطبع، آليات التحقق من الهوية والصلاحيات (Authentication & Authorization) لكل حقل.

فكر في التخزين المؤقت (Caching)

التخزين المؤقت في GraphQL يختلف قليلاً عن REST. في الواجهات الأمامية، مكتبات مثل Apollo Client و Relay تقوم بعمل رائع في تخزين نتائج الاستعلامات تلقائياً. أما على الخادم، فاستخدام أداة مثل DataLoader يعتبر ضرورياً لمنع تكرار جلب نفس البيانات عدة مرات ضمن الاستعلام الواحد (حل مشكلة N+1).

GraphQL ليس الحل السحري لكل شيء

صحيح أني أحب GraphQL، لكنها ليست دائماً الحل الأمثل. للمهام البسيطة جداً، أو للتعامل مع الملفات (File Uploads)، قد يكون استخدام REST API بسيطاً أسهل وأسرع. دائماً اختر الأداة المناسبة للمهمة، ولا تقع في فخ “المطرقة الذهبية” (عندما يكون لديك مطرقة، كل شيء يبدو كمسمار).

الخلاصة: هل يجب أن أتعلم GraphQL؟

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

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

أتمنى أن تكون هذه المقالة مفيدة، وبالتوفيق في رحلتكم البرمجية!

أبو عمر

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

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

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

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

آخر المدونات

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

تطبيقنا كان على وشك الاختفاء: كيف أنقذتني استراتيجية “الاستعداد النشط” (Active-Active) من كارثة محققة؟

في صباح ذلك اليوم، استيقظت على كارثة: منطقة سحابية رئيسية تعطلت بالكامل. في هذه المقالة، أروي لكم يا جماعة كيف أنقذت استراتيجية "الاستعداد النشط" (Active-Active)...

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

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

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

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

كل سيرفر جديد كان قصة رعب: كيف أنقذتني ‘البنية التحتية كشيفرة’ (IaC) من فوضى الإعدادات اليدوية؟

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

26 مارس، 2026 قراءة المزيد
نصائح برمجية

شفرتي كانت هرماً من الشروط المتداخلة: كيف أنقذتني ‘شروط الحماية’ (Guard Clauses) من كابوس الـ if/else؟

هل تعاني من شفرات برمجية معقدة ومليئة بالـ if/else المتداخلة؟ في هذه المقالة، أشاركك تجربتي الشخصية وكيف ساعدتني تقنية "شروط الحماية" (Guard Clauses) في تحويل...

26 مارس، 2026 قراءة المزيد
​معمارية البرمجيات

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

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

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