واجهاتي كانت تغرق في بيانات لا تحتاجها: كيف أنقذني GraphQL من جحيم الطلبات المتعددة والإفراط في جلب البيانات؟

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

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

وهون بلشت المأساة… عشان أجيب هاي المعلومات، كنت مضطر أعمل 3 طلبات منفصلة من الواجهة الأمامية (Frontend):

  1. طلب لـ /api/users/{userId} عشان أجيب معلومات المستخدم.
  2. طلب لـ /api/users/{userId}/posts عشان أجيب منشوراته.
  3. طلب لـ /api/users/{userId}/friends عشان أجيب أصدقائه.

المشكلة ما كانت بس في عدد الطلبات. الطلب الأول /api/users/{userId} كان يرجعلي كل إشي بيعرفه السيرفر عن المستخدم: اسمه، إيميله، تاريخ ميلاده، عنوانه، آخر مرة سجل فيها دخول، وحتى معلومات حساسة ما إلها أي لزمة في صفحته الشخصية! هاي الظاهرة اللي اسمها “Over-fetching” أو “الإفراط في جلب البيانات”.

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

وبعد بحث طويل وقراءة وتجريب، تعرفت على تقنية اسمها GraphQL. في البداية كنت متشكك، بس لما فهمت مبدأها، حسيت كأني لقيت الكنز المفقود. ومن يومها، تغيرت علاقتي مع الـ APIs للأبد.

ما هي GraphQL؟ ولماذا هي ليست مجرد “REST جديدة”؟

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

خليني أبسطها بزيادة. تخيل أنك في مطعم:

  • نموذج REST: أنت تطلب وجبة محددة من القائمة، مثلاً “وجبة رقم 5”. المطعم سيحضر لك الوجبة كما هي محددة مسبقاً، مع طبق رئيسي، طبق جانبي، سلطة، ومشروب. حتى لو كنت تريد الطبق الرئيسي فقط، ستصلك الوجبة كاملة. كل “وجبة” هي عبارة عن Endpoint في الـ API.
  • نموذج GraphQL: أنت أمام “بوفيه مفتوح”. تذهب إلى الشيف (الـ API Endpoint الوحيد) وتقول له بالضبط ماذا تريد: “أريد قطعة من اللحم المشوي، ملعقتين من الأرز، وبضع أوراق من الخس”. ستحصل على طبق يحتوي فقط على ما طلبته، لا أكثر ولا أقل.

هذا هو جوهر GraphQL: العميل (Client) هو من يقرر البيانات التي يحتاجها بالضبط، وليس الخادم (Server).

المشكلة الكلاسيكية: جحيم الطلبات المتعددة والإفراط في الجلب (Over-fetching)

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

مثال عملي مع REST API

كان على المطور في الواجهة الأمامية كتابة كود يشبه هذا (باستخدام JavaScript كمثال):


// الطلب الأول: جلب معلومات المستخدم
const userResponse = await fetch('https://api.example.com/users/123');
const userData = await userResponse.json(); 
// userData يحتوي على 50 حقلاً لا نحتاجها! (Over-fetching)

// الطلب الثاني: جلب منشورات المستخدم
const postsResponse = await fetch('https://api.example.com/users/123/posts?limit=10');
const postsData = await postsResponse.json();

// الطلب الثالث: جلب أصدقاء المستخدم
const friendsResponse = await fetch('https://api.example.com/users/123/friends?limit=5');
const friendsData = await friendsResponse.json();

// الآن، قم بتجميع كل هذه البيانات لعرضها في الواجهة...

المشاكل هنا واضحة:

  • تعدد الطلبات (Multiple Round-trips): ثلاثة رحلات ذهاب وإياب بين العميل والخادم، مما يزيد من زمن التحميل الكلي.
  • الإفراط في الجلب (Over-fetching): الطلب الأول /users/123 قد يعيد كائن JSON ضخمًا، بينما كل ما نحتاجه هو الاسم والصورة.
  • الجلب الناقص (Under-fetching): أحيانًا، قد لا يوفر Endpoint واحد كل ما تحتاجه، فتضطر لعمل طلبات إضافية للحصول على تفاصيل مرتبطة، مما يؤدي إلى مشكلة N+1 المعروفة.

الحل السحري: كيف يعالج GraphQL هذه المشاكل؟

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

طلب واحد يحكمهم جميعًا (One Request to Rule Them All)

بدلاً من ثلاثة طلبات، نرسل طلبًا واحدًا فقط إلى الخادم، وهذا الطلب يبدو هكذا:


query GetUserProfilePage {
  user(id: "123") {
    name
    profilePictureUrl
    
    posts(first: 10) {
      id
      title
      createdAt
    }
    
    friends(first: 5) {
      id
      name
    }
  }
}

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


{
  "data": {
    "user": {
      "name": "أبو عمر الفلسطيني",
      "profilePictureUrl": "https://example.com/abu-omar.jpg",
      "posts": [
        {
          "id": "post1",
          "title": "مقالتي عن GraphQL",
          "createdAt": "2023-10-27T10:00:00Z"
        },
        // ... 9 منشورات أخرى
      ],
      "friends": [
        {
          "id": "friend1",
          "name": "أحمد"
        },
        // ... 4 أصدقاء آخرين
      ]
    }
  }
}

لاحظ الجمال هنا:

  1. طلب واحد فقط.
  2. لا يوجد أي بيانات زائدة (No Over-fetching). حصلنا فقط على الحقول التي طلبناها.
  3. البيانات مرتبطة وجاهزة. لا حاجة لتجميعها في الواجهة الأمامية.

مفاهيم GraphQL الأساسية للمبتدئين

إذا أعجبك ما رأيته حتى الآن، فإليك شرح مبسط لأهم المفاهيم التي تحتاجها لتبدأ:

المخطط (Schema) والأنواع (Types)

الـ Schema هو قلب أي GraphQL API. إنه العقد المبرم بين العميل والخادم الذي يصف كل البيانات الممكنة التي يمكنك طلبها. يتم كتابته بلغة تعريف المخطط (Schema Definition Language – SDL).


# يصف كائن المستخدم
type User {
  id: ID!
  name: String!
  profilePictureUrl: String
  posts(first: Int = 10): [Post!]
  friends(first: Int = 10): [User!]
}

# يصف كائن المنشور
type Post {
  id: ID!
  title: String!
  content: String
  createdAt: String!
  author: User!
}

# نقطة البداية لكل الاستعلامات
type Query {
  user(id: ID!): User
  post(id: ID!): Post
}

الاستعلامات (Queries)

هي الطريقة التي “تقرأ” بها البيانات، وهي تعادل طلبات GET في عالم REST. لقد رأينا مثالًا عليها بالفعل.

التغييرات (Mutations)

عندما تريد “تغيير” البيانات (إنشاء، تحديث، حذف)، فإنك تستخدم الـ Mutations. هي تعادل طلبات POST, PUT, DELETE في REST. الميزة هنا أنها، مثل الاستعلامات، يمكنها أن تعيد البيانات التي تم تغييرها في نفس الطلب.


mutation CreateNewPost($title: String!, $content: String!) {
  createPost(title: $title, content: $content) {
    id
    title
    createdAt
    author {
      name
    }
  }
}

بعد تنفيذ هذا الـ Mutation، ستحصل مباشرة على بيانات المنشور الجديد الذي أنشأته، مما يسهل تحديث الواجهة فورًا.

المُحلّلات (Resolvers)

هذا هو الجزء الذي يعمل في الخفاء على الخادم. الـ Resolver هو دالة (function) مسؤولة عن جلب البيانات لحقل معين في الـ Schema. لكل حقل في الـ Type الخاص بك، هناك Resolver مقابل له.

على سبيل المثال، الـ Resolver الخاص بحقل user(id: ID!) قد يقوم بعمل استعلام من قاعدة البيانات، بينما الـ Resolver الخاص بحقل posts قد يقوم باستعلام آخر لجلب المنشورات المرتبطة بهذا المستخدم. GraphQL تتولى تنسيق كل هذا بذكاء.

نصائح من “أبو عمر”: متى تستخدم GraphQL؟ ومتى تبتعد عنه؟

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

استخدم GraphQL عندما…

  • تطبيقاتك تحتاج بيانات من مصادر متعددة: إذا كانت واجهتك الأمامية تحتاج لجلب بيانات من عدة خدمات مصغرة (Microservices)، فإن GraphQL يمكن أن يعمل كواجهة موحدة (Gateway) تجمع كل هذه البيانات في طلب واحد.
  • لديك عدة عملاء (ويب، موبايل، إلخ): تطبيق الموبايل يحتاج بيانات أقل من تطبيق الويب. GraphQL يسمح لكل عميل بطلب ما يحتاجه بالضبط دون الحاجة لإنشاء Endpoints مخصصة لكل منهم.
  • تريد تسريع تطوير الواجهة الأمامية: مطورو الواجهة الأمامية لا يحتاجون لانتظار فريق الواجهة الخلفية لإنشاء Endpoints جديدة. طالما أن الحقل موجود في الـ Schema، يمكنهم طلبه.

فكر مرتين قبل استخدام GraphQL عندما…

  • مشروعك بسيط جدًا: إذا كان تطبيقك عبارة عن واجهة بسيطة مع عدد قليل من الـ Endpoints الثابتة (مثل مدونة شخصية بسيطة)، فإن تعقيد إعداد GraphQL قد لا يكون مبررًا. REST API قد يكون أسرع وأسهل في هذه الحالة.
  • التعامل مع الملفات: تحميل الملفات (File Uploads) في GraphQL ممكن ولكنه ليس مباشرًا كما في REST، ويتطلب إعدادات إضافية.

  • فريقك غير مستعد للمنحنى التعليمي: GraphQL يتطلب تغييرًا في طريقة التفكير. إذا كان فريقك مضغوطًا بالوقت وغير مستعد لتعلم تقنية جديدة، فقد يؤدي ذلك إلى إبطاء المشروع في البداية.

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

الخلاصة: هل GraphQL هو نهاية REST API؟ 🏁

بالتأكيد لا. REST ما زالت تقنية رائعة ومناسبة جدًا للكثير من الحالات، خاصة في التواصل بين الخوادم (Server-to-Server) أو في الـ APIs العامة البسيطة. لكن GraphQL جاء ليحل مجموعة محددة ومؤلمة من المشاكل التي عانينا منها لسنوات، خاصة في بناء واجهات المستخدم الحديثة والمعقدة.

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

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

أبو عمر

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

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

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

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

آخر المدونات

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

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

أشارككم قصة حقيقية من بداياتي في البرمجة، حين كادت طلبات العملاء المتزامنة أن تدمر مخزون متجري الإلكتروني. اكتشفوا معي كيف أنقذتني "معاملات قاعدة البيانات" (Transactions)...

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

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

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

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

مقابلاتي التقنية كانت اختبارات صامتة: كيف أنقذني ‘التفكير بصوت عالٍ’ من جحيم الرفض رغم معرفتي بالحل؟

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

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

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

أشارككم قصة حقيقية عن معاناة تطبيق عالي الأداء مع "فقدان الذاكرة" وكيف كان التخزين المؤقت الموزع (Distributed Caching) باستخدام Redis هو طوق النجاة. مقال عملي...

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

سباق مع الزمن ضد المحتالين: كيف تبني نظامًا لكشف الاحتيال المالي في الوقت الفعلي باستخدام تعلم الآلة؟

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

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

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

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

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

اجتماعاتي مجرد تقارير حالة: كيف أنقذتني ‘الاجتماعات الفردية الفعالة’ من جحيم الفرق الصامتة؟

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

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

اختباراتي كانت خضراء لكن الكود مليء بالعلل: كيف أنقذني ‘الاختبار الطفري’ (Mutation Testing) من جحيم الثقة الزائفة؟

أشارككم قصة حقيقية حول كيف خدعتني الاختبارات "الخضراء" وأدخلت علة حرجة إلى الإنتاج. سأشرح لكم تقنية "الاختبار الطفري" (Mutation Testing) التي غيرت مفهومي عن جودة...

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