يا جماعة الخير، خليني أحكيلكم قصة صارت معي قبل كم سنة، قصة خلتني أعيد التفكير في كل شي تعلمته عن بناء الواجهات البرمجية (APIs). وقتها كنت شغال على مشروع تطبيق اجتماعي، زي فيسبوك صغير هيك، وكان مطلوب مني أبني صفحة الملف الشخصي للمستخدم.
للوهلة الأولى، المهمة بدت بسيطة: اسم المستخدم وصورته، آخر 10 منشورات إله، وأول 5 أصدقاء في قائمته. “بسيطة!”، قلت في نفسي. وبديت الشغل باستخدام REST API اللي كنا معتمدينها في المشروع.
وهون بلشت المأساة… عشان أجيب هاي المعلومات، كنت مضطر أعمل 3 طلبات منفصلة من الواجهة الأمامية (Frontend):
- طلب لـ
/api/users/{userId}عشان أجيب معلومات المستخدم. - طلب لـ
/api/users/{userId}/postsعشان أجيب منشوراته. - طلب لـ
/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 أصدقاء آخرين
]
}
}
}
لاحظ الجمال هنا:
- طلب واحد فقط.
- لا يوجد أي بيانات زائدة (No Over-fetching). حصلنا فقط على الحقول التي طلبناها.
- البيانات مرتبطة وجاهزة. لا حاجة لتجميعها في الواجهة الأمامية.
مفاهيم 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 قد يكون أسرع وأسهل في هذه الحالة.
- فريقك غير مستعد للمنحنى التعليمي: GraphQL يتطلب تغييرًا في طريقة التفكير. إذا كان فريقك مضغوطًا بالوقت وغير مستعد لتعلم تقنية جديدة، فقد يؤدي ذلك إلى إبطاء المشروع في البداية.
– التعامل مع الملفات: تحميل الملفات (File Uploads) في GraphQL ممكن ولكنه ليس مباشرًا كما في REST، ويتطلب إعدادات إضافية.
نصيحة أبو عمر: إذا كنت مترددًا، لا تقم بتحويل مشروعك الحالي بالكامل إلى GraphQL. ابدأ بمشروع جانبي صغير، أو قم ببناء واجهة GraphQL “فوق” واجهات REST API الموجودة لديك. هذا سيسمح لك بتجربة قوتها دون المخاطرة بإعادة كتابة كل شيء.
الخلاصة: هل GraphQL هو نهاية REST API؟ 🏁
بالتأكيد لا. REST ما زالت تقنية رائعة ومناسبة جدًا للكثير من الحالات، خاصة في التواصل بين الخوادم (Server-to-Server) أو في الـ APIs العامة البسيطة. لكن GraphQL جاء ليحل مجموعة محددة ومؤلمة من المشاكل التي عانينا منها لسنوات، خاصة في بناء واجهات المستخدم الحديثة والمعقدة.
بالنسبة لي، لم تكن GraphQL مجرد تقنية جديدة، بل كانت نقلة نوعية في الإنتاجية وتجربة المطور. لقد أنقذتني من “جحيم الطلبات المتعددة” وحررت واجهاتي الأمامية من عبء البيانات غير الضرورية.
نصيحتي الأخيرة لك: لا تخف من تجربتها. ابدأ صغيرًا، اقرأ التوثيق الرسمي، وجرب بناء API بسيطة. ستكتشف بنفسك مدى القوة والمرونة التي تقدمها. جرّبها، ومش راح تندم! 😉