كنت أغرق في بحر من الـ Endpoints: كيف أنقذني GraphQL من فوضى واجهات REST؟

مقدمة: قصة فنجان قهوة وكابوس الـ Endpoints

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

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

كنت أقضي صباحي مع فنجان القهوة وأنا أكتب الـ endpoints الجديدة. /users عشان تجيب المستخدمين، /posts عشان المنشورات، /users/:id/posts عشان تجيب منشورات مستخدم معين. شعور بالإنجاز، صح؟

لكن مع الوقت، كبر المشروع، وصار معنا فريق لتطبيق الموبايل (iOS و Android) وفريق للويب. وهنا بلش وجع الراس. فريق الويب بده يعرض اسم المستخدم وصورته وآخر 3 منشورات إله في الصفحة الرئيسية. فريق الموبايل بده يعرض بس اسم المستخدم وصورته في قائمة الأصدقاء. فريق تاني بده إحصائيات عن عدد الإعجابات والتعليقات لكل منشور.

فجأة، لقيت حالي بغرق. كل يوم طلبات جديدة: “أبو عمر، ممكن تعمللنا endpoint جديدة بس بترجع عدد التعليقات؟ الـ endpoint الحالية بترجع كل التعليقات وهذا بطيء عالموبايل”. “أبو عمر، بدنا نعدل الـ endpoint تبعت البروفايل عشان تضيف تاريخ الميلاد، بس ما بدنا إياها تظهر في نسخة الويب”.

صرت أعمل endpoints مخصصة لكل شاشة ولكل جهاز: /users/:id/summary، /posts/:id/stats، /mobile/v2/feed. الكود صار عبارة عن متاهة من الـ endpoints المتشابهة والمكررة، وكل تعديل صغير في مكان كان يتطلب تعديلات في 5 أماكن ثانية. حسيت إني مش مبرمج، حسيت إني “ترزي” بقعد أفصّل endpoints على مقاس كل واحد. وفي ليلة من الليالي، وأنا براجع كمية الـ endpoints اللي عملتها، قلت لحالي: “لهون وبس، لازم في حل أحسن”. وهون كانت بداية رحلتي مع GraphQL.

ما هي مشكلة REST API بالضبط؟

قبل ما نحكي عن المنقذ GraphQL، خلينا نفهم أصل المشكلة مع REST. معمارية REST عظيمة، وبسيطة، وخدمتنا لسنوات. فكرتها قائمة على “المصادر” (Resources). كل إشي هو مصدر، ولكل مصدر عنوان (URL) خاص فيه. لكن هاي البساطة هي نفسها اللي بتخلق مشاكل في التطبيقات المعقدة.

المشكلة الأولى: الجلب الزائد للبيانات (Over-fetching)

لما تطلب بيانات مستخدم من خلال endpoint مثل GET /api/users/1، السيرفر بقرر شو البيانات اللي رح يرجعها. غالبًا، رح يرجعلك كل معلومات المستخدم الموجودة في قاعدة البيانات.


// Request
GET /api/users/1

// Response
{
  "id": 1,
  "name": "أبو عمر",
  "email": "abu.omar@example.com",
  "birthdate": "1985-01-15T00:00:00.000Z",
  "address": "القدس، فلسطين",
  "createdAt": "2020-05-10T12:00:00.000Z",
  "bio": "مبرمج يحب القهوة والكود النظيف."
}

لكن ماذا لو كانت واجهة المستخدم تحتاج فقط لعرض اسم المستخدم (name)؟ أنت هيك استهلكت بيانات (bandwidth) وحملت بيانات ما إلها لزوم (birthdate, address, …إلخ). تخيل هذا على تطبيق موبايل بيستخدم باقة الإنترنت المحدودة، مشكلة!

المشكلة الثانية: الجلب الناقص للبيانات (Under-fetching)

هاي المشكلة هي الوجه الآخر للعملة. لنفرض إنك بدك تعرض صفحة بروفايل المستخدم مع آخر 5 منشورات إله. باستخدام REST، أنت مضطر تعمل طلبين (أو أكثر) للسيرفر:

  1. الطلب الأول: جلب معلومات المستخدم.

    GET /api/users/1
  2. الطلب الثاني: جلب منشورات هذا المستخدم.

    GET /api/users/1/posts?limit=5

هذا يعني رحلة ذهاب وإياب مرتين بين العميل (Client) والخادم (Server)، مما يزيد من وقت التحميل ويؤثر على تجربة المستخدم. هذه المشكلة تُعرف أحيانًا بمشكلة “N+1 requests”.

GraphQL: طوق النجاة الذي كنت أبحث عنه

GraphQL مش لغة برمجة، ولا هي مكتبة، ولا إطار عمل. هي لغة استعلام (Query Language) لواجهات برمجة التطبيقات (APIs)، وكمان هي بيئة تنفيذ (Runtime) على الخادم لتلبية هذه الاستعلامات.

الفكرة عبقرية وبسيطة: بدل ما يكون عندك عشرات الـ endpoints اللي الخادم بحدد شكل استجابتها، بكون عندك endpoint واحدة فقط (عادة /graphql). العميل (Client) هو اللي بقرر شكل البيانات اللي بده إياها بالضبط، وبيرسل استعلام (Query) يوصف هاي البيانات.

نصيحة من أبو عمر: فكر في REST كأنك بتطلب وجبة من مطعم بقائمة ثابتة (Set Menu). رح تجيك الوجبة كاملة مع المقبلات والطبق الجانبي، حتى لو ما بدك إياهم. أما GraphQL، فهو أشبه بالبوفيه المفتوح، بتروح وبتعبي صحنك بس بالأشياء اللي بتحبها وبالكمية اللي بدك إياها.

كيف تعمل GraphQL؟ مثال عملي

لنفترض نفس السيناريو السابق: بدنا نعرض اسم المستخدم ومنشوراته الخمسة الأخيرة. مع GraphQL، العميل بيرسل طلب POST واحد للـ endpoint الوحيدة /graphql، وفي جسم الطلب (body) بيحط الاستعلام التالي:


query GetUserWithPosts {
  user(id: 1) {
    name
    posts(limit: 5) {
      title
      createdAt
    }
  }
}

والسيرفر رح يرجع استجابة JSON بنفس شكل الاستعلام بالضبط، لا زيادة ولا نقصان:


{
  "data": {
    "user": {
      "name": "أبو عمر",
      "posts": [
        {
          "title": "مقدمة إلى GraphQL",
          "createdAt": "2023-10-27T10:00:00.000Z"
        },
        {
          "title": "لماذا أحب Vim",
          "createdAt": "2023-10-25T14:30:00.000Z"
        },
        // ... 3 more posts
      ]
    }
  }
}

شايفين الجمال؟ طلب واحد، جاب كل البيانات اللي بدنا إياها بالضبط. لا over-fetching ولا under-fetching. الواجهة الأمامية (Frontend) صارت هي المتحكمة، وفريق الواجهة الخلفية (Backend) مثلي، صار يركز على توصيف البيانات المتاحة (Schema) وتوفيرها، بدل ما يركز على بناء endpoints مخصصة لكل شاشة.

المكونات الأساسية لـ GraphQL

عشان تفهم السحر اللي بصير، لازم تعرف 3 مفاهيم أساسية:

1. المخطط (Schema)

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

مثال على مخطط بسيط للمستخدم والمنشور:


# يمثل مستخدم في النظام
type User {
  id: ID!
  name: String!
  email: String
  posts: [Post!]
}

# يمثل منشور كتبه مستخدم
type Post {
  id: ID!
  title: String!
  content: String
  author: User!
  createdAt: String
}

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

الـ Schema موثق ذاتيًا (self-documenting). أي مطور جديد بيقدر يقرأه ويفهم كل إمكانيات الـ API فورًا. هذا إشي مرتب جدًا!

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

كما رأينا في المثال السابق، الـ Queries هي الطريقة اللي العميل بطلب فيها البيانات للقراءة. مرونتها عالية جدًا، والعميل بحدد الحقول اللي بده إياها بالضبط.

3. التعديلات (Mutations)

طيب، كيف بنعدل البيانات (إنشاء، تحديث، حذف)؟ هنا يأتي دور الـ Mutations. هي تشبه الـ Queries في تركيبتها، لكنها مخصصة لعمليات الكتابة. بالعادة، بنحطها تحت نوع خاص اسمه Mutation في الـ Schema.


type Mutation {
  createPost(title: String!, content: String): Post
  updateUser(id: ID!, name: String): User
}

ولاستخدامها، يرسل العميل طلب Mutation كالتالي:


mutation CreateNewPost {
  createPost(title: "مقالتي الجديدة", content: "محتوى المقالة...") {
    id
    title
  }
}

لاحظ أن الـ Mutation بترجع كمان بيانات، فبتقدر تطلب البيانات تبعت العنصر الجديد اللي أنشأته في نفس الطلب.

نصائح عملية من خبرة أبو عمر

بعد ما اشتغلت على GraphQL في عدة مشاريع، جمعتلكم شوية نصائح من القلب:

  • GraphQL ليست الحل لكل المشاكل: إذا كان مشروعك بسيطًا (مدونة شخصية، صفحة هبوط)، فغالبًا REST API ستكون أسهل وأسرع في التنفيذ. GraphQL تظهر قوتها الحقيقية في التطبيقات الكبيرة والمعقدة ذات العلاقات المتشعبة بين البيانات والعملاء المتعددين (ويب، موبايل، …إلخ).
  • ابدأ بالتدريج: مش ضروري تهدم كل الـ REST API اللي عندك. يمكنك بناء طبقة GraphQL فوق واجهات REST الحالية. هذا يسمى “GraphQL Wrapper”. هكذا، يستفيد فريق الـ Frontend من مزايا GraphQL فورًا، بينما تقوم أنت بترحيل المنطق تدريجيًا في الخلفية.
  • استخدم الأدوات المناسبة: عالم GraphQL مليء بالأدوات الرائعة. في جهة الخادم، مكتبات مثل Apollo Server (لـ Node.js) تسهل عليك بناء الخادم. وفي جهة العميل، مكتبات مثل Apollo Client و Relay توفر ميزات مذهلة مثل إدارة الحالة (State Management) والتخزين المؤقت (Caching).
  • انتبه للأمان والأداء: القوة الكبيرة تأتي مع مسؤولية كبيرة. بما أن العميل يستطيع طلب ما يشاء، قد يرسل استعلامًا معقدًا جدًا يستهلك موارد الخادم (مثل طلب مستخدم، ثم كل أصدقائه، ثم كل أصدقاء أصدقائه!). لحل هذا، يجب استخدام تقنيات مثل تحديد عمق الاستعلام (Query Depth Limiting)، وتحديد تعقيد الاستعلام (Query Complexity Analysis)، وبالطبع، التأكد من صلاحيات المستخدم (Authorization) داخل الـ Resolvers.

الخلاصة: هل يجب أن تتخلى عن REST؟

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

هل يجب عليك تعلمها؟ بالتأكيد. هل يجب أن تستخدمها في كل مشروع؟ لا. افهم المشكلة التي تحاول حلها أولاً، ثم اختر الأداة المناسبة. لكن في المرة القادمة التي تجد فيها نفسك تغرق في بحر من الـ Endpoints، تذكر أن هناك طوق نجاة اسمه GraphQL قد يكون هو الحل الذي تبحث عنه. 🚀

وما تخافوا تجربوا إشي جديد، أفضل استثمار هو الاستثمار في نفسك وفي معرفتك. بالتوفيق يا أبطال! 🙏

أبو عمر

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

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

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

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

آخر المدونات

أتمتة العمليات

إشعاراتنا كانت ضجيجاً والمهام تتطلب التنقل بين ألف شاشة: كيف أنقذنا ChatOps من جحيم الفوضى التشغيلية؟

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

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

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

هل تعاني من تداخل الشروط في الكود؟ أشاركك قصة حقيقية وكيف غيّرت 'شروط الحماية' (Guard Clauses) طريقة كتابتي للكود، محولةً المتاهات المعقدة إلى مسارات واضحة...

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

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

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

12 أبريل، 2026 قراءة المزيد
ذكاء اصطناعي

قرارات نموذجنا كانت صندوقاً أسود: كيف أنقذتنا تقنيات التفسير (XAI) من جحيم التنبؤات الغامضة؟

أشارككم قصة من الميدان، يوم كاد نموذج ذكاء اصطناعي "صندوق أسود" أن يورطنا في قرارات كارثية. هذه المقالة هي دليلك لفهم تقنيات الذكاء الاصطناعي القابل...

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

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

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

12 أبريل، 2026 قراءة المزيد
تجربة المستخدم والابداع البصري

تطبيقنا كان حصناً منيعاً: كيف أنقذتنا ‘معايير الوصول الرقمي (WCAG)’ من جحيم الإقصاء الرقمي؟

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

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