مقدمة: لما كان التطبيق “بِشَرّق” بالبيانات
يا جماعة الخير، السلام عليكم. معكم أخوكم أبو عمر. قبل كم سنة، كنت شغال على تطبيق اجتماعي لأحد العملاء، تطبيق فكرته بسيطة: صفحة شخصية للمستخدم، فيها شوية معلومات عنه، وآخر منشوراته، مع كم تعليق تحت كل منشور. على الورق، المشروع كان يبدو “لوز”، يعني سهل ومباشر.
بديت الشغل واستخدمت معمارية REST API المعتادة. لكن لما بلّشنا نختبر التطبيق على شبكة جوال بطيئة شوي، بدت المشاكل. الصفحة الرئيسية كانت تأخذ وقت طويل جداً للتحميل، والتطبيق كان “يعلّق” ويستهلك بطارية بشكل مش طبيعي. قعدت مع حالي وحكيت: “يا أبو عمر، شو القصة؟ الكود نظيف والسيرفر قوي!”.
بعد تحليل للشبكة، اكتشفت الكارثة. تطبيقي المسكين كان يرسل طلب (request) عشان يجيب معلومات المستخدم. بعد ما ترجع البيانات، يرسل طلب ثاني عشان يجيب قائمة منشوراته. وبعدها، لكل منشور في القائمة، كان يرسل طلب جديد عشان يجيب التعليقات! تخيلوا معي، لو المستخدم عنده 5 منشورات، إحنا بنحكي عن 1 (للمستخدم) + 1 (للمنشورات) + 5 (للتعليقات) = 7 طلبات API منفصلة بس عشان نعرض صفحة واحدة! يا زلمة، كان التطبيق زي السلحفاة وهو يحاول يجمع كل هالمعلومات.
هنا كانت بداية رحلتي للبحث عن حل، حل ينقذني من هذا الجحيم اللي اسمه “Under-fetching”، ومن توأمه الشرير “Over-fetching”. الحل كان اسمه GraphQL.
ما هو جحيم الـ Over-fetching والـ Under-fetching؟
قبل ما نغوص في تفاصيل GraphQL، خلونا نفهم بالضبط شو المشاكل اللي كنت أواجهها مع REST API التقليدية. القصة وما فيها إنها بتتلخص في مفهومين:
الـ Over-fetching (الجلب الزائد للبيانات)
هذا بيصير لما نقطة النهاية (Endpoint) في الـ API بترجعلك بيانات أكثر بكثير من اللي بتحتاجه فعلاً في واجهة المستخدم. مثلاً، عشان أعرض اسم المستخدم وصورته الشخصية في رأس الصفحة، كنت أضطر أطلب كل معلوماته من خلال /api/users/123. الرد كان يرجعلي كائن (object) ضخم فيه اسمه، عمره، تاريخ ميلاده، عنوانه، قائمة أصدقائه، وكل إعدادات حسابه. أنا كل اللي كنت محتاجه حقلين، بس استلمت ثلاثين حقل! هذا استهلاك زائد للبيانات (bandwidth) وعبء إضافي على التطبيق لمعالجة كل هالمعلومات اللي ما إلها لزوم.
الـ Under-fetching (الجلب الناقص للبيانات)
وهذا هو الكابوس اللي حكيتلكم عنه في قصتي. بيصير لما نقطة النهاية ما بتعطيك كل البيانات اللي بتحتاجها دفعة واحدة. عشان تبني شاشة معقدة، بتحتاج ترسل طلبات متعددة لعدة endpoints عشان تجمع كل القطع. مثالنا كان واضح: احتجت طلب لبيانات المستخدم، ثم طلب لمنشوراته، ثم سلسلة من الطلبات لتعليقات كل منشور. هذا الأسلوب بيخلق ما يسمى بـ “Request Waterfall” (شلال الطلبات)، وهو سبب رئيسي لبطء التطبيقات وتجربة المستخدم السيئة.
GraphQL: المنقذ الذي طال انتظاره
وسط هذا الإحباط، بدأت أسمع عن تقنية اسمها GraphQL، وهي لغة استعلام (Query Language) للـ APIs طورتها فيسبوك داخلياً عام 2012 وأطلقتها كمشروع مفتوح المصدر في 2015. الفكرة الأساسية وراها عبقرية وبسيطة بنفس الوقت.
فكر في GraphQL كأنك رايح على بوفيه مفتوح. مع REST API، أنت مضطر تاخذ طبق جاهز محدد مسبقاً من الشيف، حتى لو ما بدك كل الأصناف اللي فيه (Over-fetching)، أو يمكن تضطر ترجع كذا مرة عشان تاخذ أصناف مختلفة من أقسام مختلفة (Under-fetching). أما مع GraphQL، أنت بتدخل ومعك صحنك، وبتحكي للشيف بالضبط شو الأصناف اللي بدك ياها وبأي كمية، وهو بجهزلك إياها كلها في طبق واحد ومرة واحدة.
هذا بالضبط ما تفعله GraphQL. أنت، كمطور للواجهة الأمامية (Frontend)، بتحدد بدقة البيانات اللي محتاجها، وشكلها، والسيرفر بيرجعلك إياها بالضبط، لا زيادة ولا نقصان، وكل هذا في طلب واحد فقط!
كيف يعمل هذا السحر؟
العملية بتعتمد على ثلاثة أعمدة رئيسية:
- Schema (المخطط): هو العقد أو “المنيو” بين العميل (Client) والخادم (Server). يتم تعريفه في الخادم، ويصف كل البيانات الممكنة اللي ممكن العميل يطلبها، وأنواعها، والعلاقات بينها. هو مصدر الحقيقة الأوحد.
- Queries (الاستعلامات): هي الطلبات اللي بيرسلها العميل. بدل ما يطلب endpoint معين، هو بيكتب استعلام بيشبه كائن JSON وبيوصف فيه البيانات اللي بده إياها.
- Resolvers (المُحَلِّلات): هي دوال (functions) موجودة على الخادم. وظيفتها إنها “تعرف” من وين تجيب البيانات لكل حقل مطلوب في الـ Query. ممكن تجيبها من قاعدة بيانات، من API ثانية، أو من أي مصدر آخر.
مثال عملي: قبل وبعد GraphQL
خلينا نرجع لمثال تطبيقنا الاجتماعي ونشوف الفرق بشكل عملي.
الطريقة القديمة (REST API)
كما ذكرنا، كنا نحتاج سلسلة من الطلبات:
GET /api/users/123GET /api/users/123/postsGET /api/posts/post-abc/commentsGET /api/posts/post-def/comments- … وهكذا
الطريقة الجديدة (GraphQL)
الآن، مع GraphQL، كل اللي بحتاجه هو إرسال طلب POST واحد إلى نقطة نهاية وحيدة (عادة /graphql)، وفي جسم الطلب أضع الاستعلام التالي:
query GetUserProfilePage {
user(id: "123") {
name
profilePictureUrl
posts(first: 5) {
id
title
comments(first: 3) {
text
author {
name
}
}
}
}
}
والسيرفر سيرد بملف JSON واحد يحتوي على كل هذه البيانات المطلوبة، وبالشكل الذي طلبته تماماً. لا أكثر ولا أقل. لاحظ كيف أني طلبت الاسم وصورة الملف الشخصي فقط من المستخدم، وأول 5 منشورات، وأول 3 تعليقات لكل منشور. هذا هو قمة التحكم والمرونة.
مقارنة مباشرة: GraphQL مقابل REST
| الميزة | REST API | GraphQL |
|---|---|---|
| جلب البيانات | يتم تحديده من قبل الخادم. يعاني من Over/Under-fetching. | يتم تحديده من قبل العميل. يطلب البيانات التي يحتاجها فقط. |
| نقاط النهاية (Endpoints) | العديد من النقاط (e.g., /users, /posts). | نقطة نهاية واحدة عادة (e.g., /graphql). |
| هيكلة البيانات | لا يوجد معيار ثابت، يعتمد على التوثيق (e.g., Swagger). | مخطط (Schema) صارم يصف أنواع البيانات والعلاقات. |
| إدارة الإصدارات (Versioning) | شائعة من خلال الرابط (e.g., /v1/users, /v2/users). | يمكن تجنبها بإضافة حقول جديدة للـ Schema دون كسر القديمة. |
نصائح أبو عمر العملية
بعد الشغل على مشاريع بالتقنيتين، صار عندي شوية نصائح بحب أشاركها معكم “من الآخر”:
- متى تختار GraphQL؟ إذا كان تطبيقك يحتوي على علاقات معقدة بين البيانات (مثل شبكة اجتماعية)، أو إذا كنت تطور لعدة واجهات (ويب، جوال، ساعة ذكية) ولكل منها متطلبات بيانات مختلفة، أو إذا كان استهلاك باقة الإنترنت على الجوال أمراً حساساً. GraphQL هنا “اشي مرتب” وبيحللك مشاكل كتير.
- هل يعني هذا أن REST سيئة؟ أبداً! REST لا تزال خياراً ممتازاً وبسيطاً جداً للـ APIs الصغيرة والمباشرة، أو في معماريات الخدمات المصغرة (Microservices) حيث تكون كل خدمة مسؤولة عن نطاق محدد جداً. إذا كانت واجهتك البرمجية بسيطة مثل “أعطني قائمة المنتجات”، فلا داعي لتعقيد الأمور مع GraphQL.
- انتبه لمشكلة N+1: على الرغم من أن GraphQL تحل مشكلة شلال الطلبات من طرف العميل، إلا أنها يمكن أن تخلق مشكلة مشابهة في الخادم تسمى “N+1 Query Problem”. تأكد من استخدام أدوات مثل `DataLoader` (في بيئة Node.js) لتجميع استعلامات قاعدة البيانات وتحسين أداء الـ Resolvers.
- استثمر في الأدوات: البيئة المحيطة بـ GraphQL قوية جداً. مكتبات مثل Apollo Client و Relay تجعل التعامل مع GraphQL في الواجهة الأمامية تجربة ممتعة، حيث تدير التخزين المؤقت (caching)، وحالة الواجهة، وغيرها الكثير تلقائياً.
الخلاصة 💡
الانتقال إلى GraphQL كان نقلة نوعية في طريقة تفكيري وتطويري للتطبيقات. لقد حررتني من قيود الـ endpoints الثابتة وأعطتني (ولفريق الواجهات الأمامية) القوة لتصميم تجارب مستخدم سريعة وفعالة دون القلق بشأن “ثرثرة” الشبكة واستهلاك البيانات.
نصيحتي الأخيرة لكل مطور: لا تخف من تجربة التقنيات الجديدة. REST لن تموت، و GraphQL ليست الحل السحري لكل المشاكل. لكن فهم نقاط قوة وضعف كل منهما سيجعلك مهندساً أفضل، قادراً على اختيار الأداة المناسبة للمهمة المناسبة. ابدأ بمشروع جانبي صغير، جرب بناء GraphQL API بسيطة، وشوف بنفسك الفرق. صدقني، راح تدعيلي. 😉