كنت أغرق في بحر من الـ 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 قد يكون هو الحل الذي تبحث عنه. 🚀

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

أبو عمر

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

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

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

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

آخر المدونات

التكنلوجيا المالية Fintech

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

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

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

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

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

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

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

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

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

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

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

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

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

أشارككم قصة حقيقية عن مشروع كاد أن يفشل بسبب بطء قاعدة البيانات رغم استخدامي للتخزين المؤقت. اكتشفوا كيف كانت خوارزمية بسيطة مثل LRU هي طوق...

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

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

أشارككم قصة حقيقية من بداياتي، عندما كاد حبي للألوان الزاهية أن يدمر مشروعاً كاملاً. اكتشفوا معي كيف تعلمت بالطريقة الصعبة أهمية تباين الألوان (Color Contrast)...

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