GraphQL للمطورين في الواجهة الأمامية: دليل عملي للبدء باستخدام Apollo Client وReact
مقدمة: لماذا يهتم مطور الواجهة الأمامية بـ GraphQL؟
إذا كنت مطور Front End وتبحث عن طريقة أكثر مرونة وكفاءة للتعامل مع البيانات القادمة من API، فإن GraphQL يستحق اهتمامك. هذه التقنية لا تقتصر على جلب البيانات فقط، بل تمنح العميل قدرة دقيقة على تحديد شكل البيانات المطلوبة، وهو ما يساعد على تحسين الأداء وتقليل الاستهلاك غير الضروري للشبكة.
في هذا الدليل العملي، سنشرح أساسيات GraphQL بلغة واضحة، ثم ننتقل إلى تطبيق بسيط باستخدام React وApollo Client لبناء تطبيق يعرض قائمة من أعمال anime.

ما هو GraphQL؟
GraphQL هو query language يُستخدم للتواصل مع API بطريقة تتيح للتطبيق طلب البيانات التي يحتاجها فقط، بالشكل الذي يريده بالضبط. وهذا يختلف عن كثير من واجهات REST التقليدية التي قد تعيد بيانات أكثر أو أقل من المطلوب.
الميزة الجوهرية في GraphQL هي أن العميل يحدد:
- ما هي الحقول المطلوبة.
- كيف يجب أن تكون بنية الاستجابة.
- أي كيان أو علاقة يحتاج إلى قراءتها من الخادم.
المشكلة التي يحلها GraphQL
يعالج GraphQL مشكلتين شائعتين في جلب البيانات:
- Over Fetching: عندما يحصل التطبيق على بيانات كثيرة لا يحتاج إليها فعلياً.
- Under Fetching: عندما لا يحصل التطبيق على كل البيانات المطلوبة، فيضطر إلى تنفيذ طلبات إضافية.
على سبيل المثال، إذا كنت تريد فقط عرض userName وuserImage وName داخل صفحة الملف الشخصي، لكن الواجهة البرمجية ترسل مع ذلك تفاصيل أخرى كثيرة غير مستخدمة، فأنت هنا أمام حالة Over Fetching.
أما إذا أرسلت الواجهة البرمجية جزءاً ناقصاً من البيانات، واضطررت إلى تنفيذ طلب آخر لاستكمال الحقول اللازمة، فهذه حالة Under Fetching.

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

كيف تبدأ مع GraphQL؟
قبل بناء أي مشروع فعلي، من المهم التعرف إلى بعض المفاهيم الأساسية والأدوات التي تسهّل تجربة التطوير.
GraphQL Playground
GraphQL Playground عبارة عن بيئة رسومية تفاعلية تساعدك على استكشاف الخادم وتنفيذ الاستعلامات بسهولة. يمكنك من خلالها تجربة queries المختلفة ومعاينة النتائج مباشرة.
تُعد هذه الأداة مناسبة جداً في المراحل الأولى من التعلم، لأنها تمنحك فهماً بصرياً واضحاً لبنية البيانات وطريقة كتابة الاستعلامات.

عند الضغط على زر التشغيل، يتم تنفيذ الاستعلام وعرض النتيجة فوراً.
كيف نطلب البيانات أو نرسلها في GraphQL؟
في GraphQL نستخدم:
- query لقراءة البيانات.
- mutation لإضافة البيانات أو تعديلها أو حذفها.
الصيغة الأساسية لأي عملية تكون كالتالي:
GraphQLOperatoinType Name {
....
........
.....
...
}
أما الاستعلام البسيط فيُكتب بهذه الصورة:
query getData {
...
}
وبالمثل، إذا أردت تنفيذ عملية كتابة بيانات، يمكنك استبدال query بـ mutation.
استكشاف البيانات باستخدام Apollo Studio
بعد تجربة GraphQL Playground، ستجد أن Apollo Studio يوفر تجربة أكثر سلاسة، خاصة لمطور الواجهة الأمامية. فمن خلاله يمكنك اختيار الحقول المطلوبة من الواجهة الرسومية، ليقوم بإنشاء الاستعلام تلقائياً.
كل ما عليك فعله هو تحديد الحقول من الجهة اليسرى، وستحصل على query جاهز يمكنك نسخه مباشرة إلى مشروعك.

بناء تطبيق Anime بسيط باستخدام GraphQL وReact
سنستخدم في هذا المثال Anilist API للحصول على قائمة من أعمال anime. التطبيق سيكون مبنياً باستخدام React، لكن الفكرة نفسها قابلة للتطبيق في أي مكتبة أو إطار عمل آخر.
إنشاء مشروع React جديد
ابدأ بإنشاء مشروع جديد عبر الأمر التالي:
npx create-react-app graphql-example
بعد إنشاء المشروع، انتقل إلى المجلد وثبّت الحزم المطلوبة:
npm install graphql @apollo/client
إعداد Apollo Client
الخطوة التالية هي إعداد Apollo Client داخل الملف src/index.js. قم أولاً باستيراد الأدوات الأساسية:
import {ApolloClient, InMemoryCache, ApolloProvider} from '@apollo/client' ;
ApolloClient هو الكائن المسؤول عن إدارة الاتصال مع خادم GraphQL. عند إنشائه، نحتاج عادة إلى أمرين أساسيين:
- uri: عنوان خادم GraphQL.
- cache: آلية تخزين مؤقت تساعد على تقليل الطلبات وتحسين الأداء.
ويكون الإعداد على النحو التالي:
const client = new ApolloClient({
uri : 'https://graphql.anilist.co/' ,
cache : new InMemoryCache(),
})
بعد ذلك، اجعل هذا العميل متاحاً لجميع مكونات التطبيق عبر تغليف المكون الأعلى بـ ApolloProvider.
كتابة أول Query
الآن بعد اكتمال الإعداد الأولي، حان وقت تنفيذ أول استعلام. سنستخدم useQuery لجلب البيانات، لكن قبل ذلك علينا تعريف الاستعلام باستخدام gql.
قم أولاً باستيراد الأداتين:
import {useQuery, gql} from '@apollo/client' ;
ثم عرّف الاستعلام بالشكل التالي:
const AnimeList = gql `
query Query {
Page {
media {
siteUrl
title {
english
native
}
description
coverImage {
medium
}
bannerImage
volumes
episodes
}
}
}
` ;
جلب البيانات باستخدام useQuery
بعد تعريف الاستعلام، يمكنك تنفيذه مباشرة باستخدام useQuery:
const {loading, error, data} = useQuery(AnimeList);
تُرجع هذه الدالة ثلاث حالات مهمة:
- loading: لمعرفة ما إذا كان الطلب لا يزال قيد التنفيذ.
- error: لمعالجة الأخطاء المحتملة.
- data: للوصول إلى البيانات عند نجاح الطلب.
وللتحقق من عمل التطبيق في البداية، يمكن عرض البيانات بشكل خام:
if (loading) return ( <> Loading </> );
if (error) return ( <> {JSON.stringify(error)} </> )
return ( <> {JSON.stringify(data)} </> );

تنسيق واجهة التطبيق وعرض قائمة Anime
بعد التأكد من وصول البيانات، يمكننا عرضها بشكل أكثر أناقة. ومن الأفضل هنا استخدام optional chaining لتفادي الأخطاء الناتجة عن القيم غير الجاهزة أثناء التحميل.
<div className= "container" >
< h1 > 🐈 Anime List </ h1 >
< hr width = "80%" />
{data?.Page?.media.map( anime => (
<>
< div className = "card" >
< img src = {anime.coverImage.medium}/ >
< div >
< h1 > {anime.title.english} </ h1 >
< div className = "episodes" >
Episodes < b > {anime.episodes} </ b >
</ div >
< div dangerouslySetInnerHTML = {{__html: anime.description }} > </ div >
</ div >
</ div >
< hr width = "75%" />
</>
))}
<div className= "buttonContainer" >
{ page != 1 && < button > Previous Page </ button > }
<div className= "pageText" >{page}</div>
<button onClick = {NextPage} > Next Page </ button >
</div>
</div>);

التعامل مع Variables في GraphQL
حتى الآن نحن نجلب صفحة واحدة فقط من النتائج. لكن ماذا لو أردنا الانتقال بين الصفحات؟ هنا يأتي دور variables في GraphQL.
من خلال Apollo Studio يمكنك إضافة متغير page بسهولة عبر قسم arguments داخل المسار root > query > page.

عند النقر على page سيُضاف المتغير إلى الاستعلام، ويمكنك تغيير قيمته من قسم variables لمعاينة نتائج صفحات مختلفة.

تمرير المتغيرات داخل التطبيق
داخل تطبيق React سنستخدم useState لتتبع الصفحة الحالية، ثم نمرر القيمة إلى useQuery.
const [page, setPage] = useState( 1 );
//this is how we would be passing the page in the query.
const {loading, error, data} = useQuery(AnimeList , {
variables : { "page" : page }
});
const NextPage = () => {
setPage(page+ 1 );
}
const PreviousPage = () => {
setPage(page - 1 );
}
<div className= "buttonContainer" >
{ page != 1 && < button onClick = {PreviousPage} > Previous Page </ button > }
<div className= "pageText" >{page}</div>
<button onClick = {NextPage} > Next Page </ button >
</div>
بهذه الطريقة يصبح التطبيق قادراً على جلب الصفحة التالية أو السابقة ديناميكياً، دون الحاجة إلى إعادة بناء منطق الاتصال كاملاً.
مزايا GraphQL لمطوري Front End
بعد هذا المثال العملي، يمكن تلخيص أهم فوائد GraphQL لمطوري الواجهة الأمامية في النقاط التالية:
- تقليل البيانات غير الضرورية المرسلة من الخادم.
- الحصول على استجابة مصممة وفق احتياجات الواجهة فقط.
- تقليل عدد الطلبات في الحالات التي تتطلب بيانات مترابطة.
- تجربة تطوير أفضل بفضل أدوات مثل Apollo Studio وGraphQL Playground.
- سهولة إدارة البيانات في تطبيقات React عبر Apollo Client.
أفضل ممارسات عند استخدام GraphQL في المشاريع الحقيقية
1. لا تطلب إلا ما تحتاجه
رغم أن GraphQL يمنحك حرية تحديد الحقول، فإن بعض المطورين يقعون في خطأ طلب حقول كثيرة لمجرد أنها متاحة. الأفضل دائماً هو الالتزام بالحد الأدنى المطلوب للواجهة.
2. استفد من التخزين المؤقت
استخدام InMemoryCache ليس مجرد إعداد إضافي، بل عنصر مهم لتحسين الأداء وتقليل الضغط على الشبكة، خصوصاً في التطبيقات التفاعلية.
3. راقب معالجة الأخطاء
ينبغي عرض رسائل مناسبة للمستخدم عند حدوث فشل في الطلب، وعدم الاكتفاء بطباعة الخطأ تقنياً فقط، خاصة في التطبيقات الإنتاجية.
4. نظّف المحتوى المعروض من API
في المثال السابق استُخدم dangerouslySetInnerHTML لعرض الوصف. هذه الطريقة مفيدة أحياناً، لكنها تتطلب حذراً شديداً عند التعامل مع محتوى HTML لتجنب الثغرات الأمنية.
الخلاصة التقنية
GraphQL ليس مجرد بديل تقني عن REST، بل هو أسلوب أكثر ذكاءً في إدارة تدفق البيانات بين الواجهة الأمامية والخادم. بالنسبة لمطور Front End، تكمن قيمته الحقيقية في القدرة على بناء واجهات أسرع وأكثر دقة، مع تقليل الهدر في الطلبات وتحسين تجربة التطوير. وعند دمجه مع Apollo Client وReact، يصبح من السهل إنشاء تطبيقات حديثة مرنة وقابلة للتوسع، خاصة عندما تكون بنية البيانات معقدة أو متغيرة باستمرار.