يا جماعة الخير، السلام عليكم. اسمي أبو عمر، مبرمج قضيت سنين طويلة من عمري بين الأكواد والخوارزميات، من أيام ما كنا نكتب الكود على شاشات سوداء بخط أخضر لحد اليوم مع السحابة والذكاء الاصطناعي. خليني اليوم أحكيلكم قصة صارت معي قبل كم سنة، قصة علمتني درس كبير عن بناء الواجهات البرمجية (APIs) وكيف إن اختيار الأداة الصح ممكن ينقذ مشروعك من “وجع راس” كبير.
كنا شغالين على تطبيق موبايل، فكرته كانت تجمع بين المحتوى الاجتماعي والتجارة الإلكترونية. التطبيق كان فيه صفحة رئيسية بتعرض للمستخدم اسمه وصورة بروفايله، وآخر منتج أضافه، وعدد التعليقات على هاد المنتج. فريق الواجهة الأمامية (Frontend) كانوا شباب شاطرين، بس كل يوم يجوني يشتكوا: “يا أبو عمر، التطبيق بطيء! الصفحة الرئيسية بتاخد 5 ثواني عشان تفتح!”.
أنا بصراحة استغربت، السيرفرات قوية وقاعدة البيانات معمولة صح. قعدت معهم، وفتحنا أدوات المطورين لنشوف “شو القصة”. وهون كانت الصدمة. عشان يعرضوا هاي المعلومات البسيطة، كانوا مضطرين يعملوا 3 طلبات API مختلفة لـ REST API اللي بنيناه:
- طلب لـ
/api/user/{id}عشان يجيبوا معلومات المستخدم. - طلب ثاني لـ
/api/user/{id}/productsعشان يجيبوا كل منتجاته، وبعدين يفلتروها في التطبيق نفسه ليلاقوا آخر منتج. - طلب ثالث لـ
/api/products/{productId}/commentsعشان يجيبوا كل التعليقات ويعدّوها.
والمصيبة الأكبر كانت في الطلب الأول تبع المستخدم. الـ API كان يرجع كائن JSON ضخم فيه كل شي: تاريخ ميلاده، عنوانه، سجل مشترياته، آخر مرة سجل دخول… بيانات ما إلنا فيها أي لزوم في الصفحة الرئيسية! كان التطبيق يستقبل كل هاي البيانات ويرمي 95% منها. هون أدركت إننا غرقانين في جحيم اسمه الـ Over-fetching والـ Under-fetching. ومن هاي النقطة، بدأت رحلتي مع GraphQL.
تشخيص المشكلة: ما هو الـ Over-fetching والـ Under-fetching؟
قبل ما نحكي عن الحل، خلينا نفهم أصل المشكلة اللي كل مطور تعامل مع REST APIs أكيد مر فيها. هدول المصطلحين هما سبب كثير من مشاكل الأداء في تطبيقاتنا.
الـ Over-fetching: لما تجيب بضاعة ما إلك فيها لزوم
الـ Over-fetching، أو “الجلب الزائد”، بيصير لما تطلب معلومة بسيطة من الـ API، فيقوم السيرفر بإرجاع كمية هائلة من البيانات اللي ما بتحتاجها. تخيل إنك بدك بس اسم المستخدم وصورته، بس الـ API مصمم يرجعلك كل بيانات المستخدم في طلب واحد.
مثال من العالم القديم (REST API):
لو عملنا طلب GET /api/users/123، ممكن يرجعلنا إشي زي هيك:
{
"id": 123,
"username": "abu_omar",
"email": "abuomar@example.com",
"profile_picture": "url/to/image.jpg",
"first_name": "عمر",
"last_name": "أحمد",
"address": {
"street": "شارع القدس",
"city": "نابلس",
"country": "فلسطين"
},
"phone_number": "+970...",
"created_at": "2020-01-15T09:30:00Z",
"last_login": "2023-10-26T10:00:00Z",
"order_history": [ ... 50 عنصر ... ]
}
في الصفحة الرئيسية، كل اللي كنا محتاجينه هو username و profile_picture. كل البيانات الباقية هي عبء على الشبكة، بتستهلك باقة الإنترنت تبعت المستخدم، وبتبطئ التطبيق لأنه بحاجة يحلل كل هذا الـ JSON الضخم.
الـ Under-fetching: مشوار الألف ميل اللي ببدأ بمليون طلب
الـ Under-fetching، أو “الجلب الناقص”، هو الوجه الآخر للمشكلة. بيصير لما نقطة النهاية (Endpoint) الواحدة في الـ API ما بتعطيك كل البيانات اللي بتحتاجها، فتضطر تعمل سلسلة من الطلبات المتتالية عشان تجمع كل المعلومات المطلوبة.
مثال من قصتنا:
عشان نعرض الصفحة الرئيسية، كنا بحاجة لـ:
- الطلب الأول:
GET /api/users/123(للحصول على معلومات المستخدم) - الطلب الثاني:
GET /api/users/123/posts(للحصول على منشوراته) - الطلب الثالث:
GET /api/posts/abc/comments(للحصول على تعليقات آخر منشور)
هذا الأسلوب، اللي بسموه أحياناً مشكلة “N+1 requests”، كارثي للأداء، خصوصاً على شبكات الموبايل البطيئة. كل طلب إضافي يعني وقت انتظار أطول للمستخدم، وتجربة استخدام سيئة.
الحل السحري: تعرف على GraphQL
بعد ما شخصنا المشكلة، كان واضح إنه REST API، برغم قوته وبساطته في كثير من الحالات، مش هو الحل الأمثل لمشكلتنا. وهنا دخلت GraphQL على الخط. GraphQL مش مكتبة ولا إطار عمل، هي “لغة استعلام” (Query Language) للـ API تبعك، وفكرة عبقرية طورتها فيسبوك عام 2012 لحل هاي المشاكل بالزبط.
شو قصة GraphQL؟
الفكرة الأساسية في GraphQL بسيطة جداً: العميل (Client) هو اللي بقرر شو البيانات اللي بده إياها، وبالضبط بالشكل اللي بده إياه.
بدل ما يكون عندك عشرات الـ Endpoints المختلفة (/users, /posts, /comments)، في GraphQL عادة بيكون عندك نقطة نهاية واحدة بس (مثلاً /graphql). العميل بيرسل طلب واحد لهذه النقطة، وفي هذا الطلب بيوصف كل البيانات اللي بيحتاجها، حتى لو كانت من مصادر مختلفة (مستخدمين، منشورات، تعليقات).
نصيحة من أبو عمر: فكر في REST API كأنه بوفيه مفتوح عنده أطباق جاهزة (Users, Posts). ممكن طبق يكون فيه أكل زيادة ما بدك إياه (Over-fetching)، وممكن تحتاج تروح وترجع كذا مرة لتجمع وجبتك (Under-fetching). أما GraphQL، فهو كأنك بتعطي الشيف قائمة طلباتك بالتفصيل، وهو بحضّرلك طبق واحد فيه كل اللي طلبته بالزبط، لا زيادة ولا نقصان.
GraphQL في الميدان: مقارنة عملية مع REST
الحكي النظري حلو، بس خلينا نشوف كيف GraphQL بحل مشاكلنا على أرض الواقع. لنرجع لمثال الصفحة الرئيسية تبعت تطبيقنا.
مثال عملي: لنبني صفحة المستخدم من جديد
بدل ما نعمل 3 طلبات منفصلة، مع GraphQL بنعمل طلب واحد فقط. العميل بيكتب “استعلام” (Query) بيشبه الـ JSON وبيبعته للسيرفر.
الطريقة الجديدة (GraphQL):
العميل يرسل طلب POST إلى /graphql مع الاستعلام التالي:
query GetHomePageData {
user(id: "123") {
username
profile_picture
latestPost {
title
commentsCount
}
}
}
شوفوا جمال وبساطة الموضوع! في طلب واحد، طلبنا: من المستخدم اللي الـ id تبعه “123”، أعطيني الـ username و الـ profile_picture، ومن آخر منشور له (latestPost)، أعطيني الـ title وعدد التعليقات (commentsCount).
والسيرفر، اللي بيفهم GraphQL، راح يرجع استجابة JSON شكلها مطابق تماماً لشكل الطلب:
{
"data": {
"user": {
"username": "abu_omar",
"profile_picture": "url/to/image.jpg",
"latestPost": {
"title": "مقدمة إلى GraphQL",
"commentsCount": 42
}
}
}
}
وهيك، بطلب واحد فقط، حصلنا على كل البيانات اللي بنحتاجها بالزبط. لا في بيانات زيادة (Over-fetching)، ولا في طلبات ناقصة (Under-fetching). كل المشاكل انحلت بضربة واحدة.
وداعاً للـ Over-fetching و الـ Under-fetching
- حل الـ Under-fetching: جمعنا بيانات من مصادر مترابطة (User, Post, Comments) في طلب شبكة واحد.
- حل الـ Over-fetching: حددنا الحقول اللي بنحتاجها بالضبط (
username,profile_picture, etc.) وما استلمنا أي بيانات إضافية.
نصائح من خبرة أبو عمر
بعد ما اشتغلت على مشاريع كثيرة باستخدام GraphQL، جمعت شوية نصائح عملية بحب أشاركها معكم.
متى تستخدم GraphQL؟ ومتى تلتزم بـ REST؟
GraphQL مش دايماً هو الحل السحري لكل شي. REST ما زال خيار ممتاز جداً في حالات كثيرة. القاعدة اللي بمشي عليها هي:
- استخدم REST: لما تكون الـ API بسيطة جداً، أو بتتعامل مع مصادر بيانات واضحة ومحددة. مثلاً، API داخلية بين خدمتين (Microservices) ممكن تكون REST أبسط وأسرع في التنفيذ.
- استخدم GraphQL: لما يكون عندك تطبيق عنده متطلبات بيانات معقدة ومتغيرة، وخصوصاً لما يكون عندك أكثر من عميل (تطبيق موبايل، موقع ويب، تطبيق ديسكتوب). GraphQL بيعطي قوة ومرونة هائلة لفريق الواجهة الأمامية (Frontend) ليطلبوا البيانات اللي بدهم إياها بدون ما يرجعوا لفريق الـ Backend كل شوي.
لا تخف من التعقيد المبدئي
بناء سيرفر GraphQL لأول مرة ممكن تحسه أصعب من بناء REST API. لازم تعرف مفاهيم جديدة زي الـ Schema (المخطط)، والـ Types (الأنواع)، والـ Resolvers (المحللات اللي بتجيب البيانات). لكن صدقني، هذا الجهد المبدئي بيوفر عليك أضعاف الوقت والجهد في المستقبل، خصوصاً لما التطبيق يكبر ويتعقد.
فكر في التخزين المؤقت (Caching)
التخزين المؤقت في REST سهل: كل URL هو معرّف فريد للبيانات، فممكن تعمل Cache على مستوى الـ HTTP. في GraphQL، كل الطلبات بتروح على نفس الـ URL (/graphql)، فالـ Caching بيختلف. لحسن الحظ، في مكتبات عملاقة زي Apollo Client و Relay بتهتم بهذا الموضوع بشكل ذكي جداً على مستوى العميل، وبتعمل Cache للبيانات بناءً على أنواعها ومعرّفاتها (IDs).
الخلاصة: هل GraphQL هو المستقبل؟ 🚀
من الآخر، GraphQL مش مجرد موضة وراح تعدي. هي أداة قوية جداً حلت مشاكل حقيقية كنا نعاني منها كمطورين لسنوات طويلة. أعطت فريق الـ Frontend استقلالية أكبر، وحسّنت أداء التطبيقات بشكل ملحوظ، وخلّت عملية تطوير وتحديث الـ APIs أكثر مرونة وسلاسة.
هل هذا يعني إن REST انتهى؟ طبعاً لأ. REST سيظل موجوداً وهو الخيار الأمثل للبساطة والوضوح في كثير من السيناريوهات. لكن أي مطور اليوم لازم يكون عنده GraphQL في صندوق أدواته، ويفهم متى وكيف يستخدمه.
نصيحتي الأخيرة إلك: لا تتردد. ابدأ اليوم بتعلم GraphQL. ابني مشروع صغير، جرب تكتب Schema، واكتب أول Query إلك. راح تكتشف عالم جديد من القوة والمرونة في التعامل مع البيانات. وبالتوفيق يا جماعة الخير!