دليل شامل: بناء تطبيق متكامل (Full-stack) باستخدام Apollo GraphQL مع React و Node.js
مكتبة Apollo Client هي حل متكامل لإدارة الحالة (State Management) في تطبيقات JavaScript. تتميز بقوتها ومرونتها، حيث يمكن استخدامها في كل من الواجهة الخلفية (Back-end) والواجهة الأمامية (Front-end). في هذا الدليل الشامل، سنستعرض كيفية الاستفادة منها في كلا الجانبين، بدءًا من بناء خادم Apollo GraphQL باستخدام Node.js، ووصولاً إلى استهلاك البيانات من جانب العميل باستخدام React.js. إذا كنت حديث العهد بـ GraphQL، سيقدم لك هذا الدليل أساسًا متينًا، وإلا فلنبدأ رحلتنا البرمجية.
بناء الخادم باستخدام Apollo و Node.js و GraphQL
في هذا القسم، سنقوم ببناء خادم GraphQL قوي باستخدام Apollo و Node.js. لاستعراض البيانات، سنعتمد على واجهة برمجة تطبيقات GitHub API العامة. الخطوة الأولى هي إعداد مشروع Node.js جديد. افتح الطرفية (Terminal) ونفذ الأمر التالي:
yarn init
بعد تهيئة المشروع بنجاح، نحتاج إلى تثبيت الحزم الضرورية لبناء الخادم. قم بتنفيذ الأمر التالي:
yarn add apollo-server graphql axios
apollo-server: الحزمة الأساسية لبناء خادمApollo GraphQL.graphql: مكتبةJavaScriptلتنفيذ استعلاماتGraphQL.axios: مكتبة قوية لإجراء طلباتHTTPمن الخادم.
الآن بعد أن أصبح لدينا جميع الحزم المطلوبة، لنقم بإنشاء ملف جديد باسم app.js في الجذر، والذي سيكون نقطة الدخول الرئيسية لخادمنا.
مخطط GraphQL (Schema)
يصف مخطط GraphQL (Schema) بنية الرسم البياني لبياناتك. إنه يحدد مجموعة من الأنواع (Types) مع حقول (Fields) يتم ملؤها من مخازن البيانات الخلفية لديك. لنضف مخططًا جديدًا إلى ملف app.js:
app.js
const { ApolloServer, gql } = require("apollo-server");
const axios = require("axios");
const typeDefs = gql`
type User {
id: ID
login: String
avatar_url: String
}
type Query {
users: [User]
}
`;
كما ترى، لم نستخدم جميع البيانات التي توفرها واجهة GitHub API. نحن بحاجة فقط إلى id الذي سيُستخدم كمفتاح مرجعي في تطبيق React، بالإضافة إلى login و avatar_url. لقد قمنا أيضًا بتعريف استعلام (Query) باسم users يعيد مصفوفة من المستخدمين ([User]). الآن بعد أن أصبح لدينا مخطط GraphQL، حان الوقت لبناء المُحللات (Resolvers) المقابلة لإكمال عملية الاستعلام.
المُحللات (Resolvers) في GraphQL
المُحلل (Resolver) هو مجموعة من الوظائف التي تساعد في إنشاء استجابة من استعلام GraphQL. لنضف مُحللاً جديدًا إلى ملف app.js:
app.js
const resolvers = {
Query: {
users: async () => {
try {
const users = await axios.get("https://api.github.com/users");
return users.data.map(({ id, login, avatar_url }) => ({
id,
login,
avatar_url,
}));
} catch (error) {
throw error;
}
},
},
};
يجب أن يتطابق المُحلل مع المخطط المناسب بالاسم. لذلك، يشير users هنا إلى استعلام users المحدد في مخططنا. إنها دالة تجلب البيانات من واجهة برمجة التطبيقات (API) بمساعدة axios وتعيد، كما هو متوقع، id و login و avatar_url. وبما أن هذه العملية قد تستغرق وقتًا لإكمالها، فقد استخدمنا async/await للتعامل معها بشكل غير متزامن. وبهذا، يمكننا الآن إنشاء خادم Apollo في القسم التالي.
إنشاء خادم Apollo GraphQL
إذا تذكرت، قمنا في ملف app.js باستيراد ApolloServer من حزمة apollo-server. إنها دالة بناء (Constructor) تستقبل كائنًا كوسيط. ويجب أن يحتوي هذا الكائن على المخطط (typeDefs) والمُحللات (resolvers) لتتمكن من إنشاء الخادم. لنعدل ملف app.js قليلًا باستخدام ApolloServer:
app.js
const server = new ApolloServer({
typeDefs,
resolvers,
});
server.listen().then(({ url }) =>
console.log(`Server ready at ${url}`)
);
هنا، نمرر كائنًا يحتوي على المخطط والمُحللات إلى ApolloServer لإنشاء الخادم، ثم نجعله يستمع للطلبات. بهذا، أصبح لدينا الآن خادم وظيفي للعمل معه. يمكنك بالفعل التفاعل معه وإرسال استعلامات باستخدام GraphQL playground عن طريق تشغيل الأمر التالي:
yarn start
يمكنك معاينته الآن على http://localhost:4000.
ملف app.js كاملاً
const { ApolloServer, gql } = require("apollo-server");
const axios = require("axios");
const typeDefs = gql`
type User {
id: ID
login: String
avatar_url: String
}
type Query {
users: [User]
}
`;
const resolvers = {
Query: {
users: async () => {
try {
const users = await axios.get("https://api.github.com/users");
return users.data.map(({ id, login, avatar_url }) => ({
id,
login,
avatar_url,
}));
} catch (error) {
throw error;
}
},
},
};
const server = new ApolloServer({
typeDefs,
resolvers,
});
server.listen().then(({ url }) =>
console.log(`Server ready at ${url}`)
);
الخادم وحده لا يفعل الكثير. نحتاج إلى إضافة نص برمجي للتشغيل (start script) في ملف package.json، كما خمنت، لبدء تشغيل الخادم. سنستخدم nodemon لإعادة تشغيل الخادم تلقائيًا عند حفظ التغييرات.
// أولاً، قم بتثبيت nodemon:
yarn add nodemon --dev
// ثم أضف السكريبت إلى package.json:
"scripts": {
"start": "nodemon app.js"
}
بهذا، أصبح لدينا خادم لجلب البيانات من GitHub API. حان الوقت الآن للانتقال إلى جانب العميل واستهلاك البيانات. لنفعل ذلك.

بناء الواجهة الأمامية باستخدام React
الخطوة الأولى في بناء الواجهة الأمامية هي إنشاء تطبيق React جديد. افتح الطرفية ونفذ الأمر التالي:
npx create-react-app client-react-apollo
بعد إنشاء التطبيق، نحتاج إلى تثبيت حزم Apollo و GraphQL الضرورية للاتصال بالخادم:
yarn add apollo-boost @apollo/react-hooks graphql
apollo-boost: حزمة تحتوي على إعدادات افتراضية لـApollo Client.@apollo/react-hooks: خطافات (Hooks) لـReactللعمل معApollo Client.graphql: مكتبةJavaScriptلتحليل استعلاماتGraphQL.
الآن، يمكننا ربط Apollo بتطبيق React الخاص بنا عن طريق تحديث ملف index.js.
ربط React بـ Apollo Client
index.js
import React from 'react';
import ReactDOM from 'react-dom';
import ApolloClient from 'apollo-boost';
import { ApolloProvider } from '@apollo/react-hooks';
import App from './App';
import './index.css';
import * as serviceWorker from './serviceWorker';
const client = new ApolloClient({
uri: 'http://localhost:4000' // تأكد من مطابقة هذا العنوان لعنوان خادمك
});
ReactDOM.render(
<React.StrictMode>
<ApolloProvider client={client}>
<App />
</ApolloProvider>
</React.StrictMode>,
document.getElementById('root')
);
serviceWorker.unregister();
كما ترى، نبدأ باستيراد ApolloClient و ApolloProvider. الأول يساعدنا في إبلاغ Apollo بعنوان URL الذي يجب استخدامه عند جلب البيانات. وإذا لم يتم تمرير uri إلى ApolloClient، فسيأخذ اسم النطاق الحالي مضافًا إليه /graphql. الثاني هو الموفر (Provider) الذي يتوقع استقبال كائن العميل (client object) ليتمكن من ربط Apollo بـ React. بعد ذلك، يمكننا الآن إنشاء مكون (Component) يعرض البيانات.
جلب البيانات من الخادم
سنقوم الآن بتعديل ملف App.js لجلب البيانات وعرضها. لنبدأ بتعريف استعلام GraphQL الذي سيجلب المستخدمين:
App.js
import React from "react";
import { useQuery } from "@apollo/react-hooks";
import gql from "graphql-tag";
import "./App.css";
const GET_USERS = gql`
{
users {
id
login
avatar_url
}
}
`;
هنا، لدينا استعلام GraphQL بسيط يجلب البيانات المطلوبة. سيتم تمرير هذا الاستعلام لاحقًا إلى الخطاف useQuery لإخبار Apollo بالبيانات التي يجب جلبها. بعد ذلك، سنقوم بإنشاء مكون تقديمي (Presentational Component) لعرض تفاصيل كل مستخدم:
App.js
const User = ({ user: { login, avatar_url } }) => (
<div className="Card">
<div>
<img alt="avatar" className="Card--avatar" src={avatar_url} />
<h1 className="Card--name">{login}</h1>
</div>
<a href={`https://github.com/${login}`} className="Card--link">
See profile
</a>
</div>
);
سيُستخدم هذا المكون لعرض معلومات المستخدم. يستقبل البيانات من مكون App ويعرضها بتنسيق جذاب.
عرض البيانات في الواجهة الأمامية
الآن، لنكمل مكون App الرئيسي لاستخدام الخطاف useQuery وعرض البيانات:
App.js
function App() {
const { loading, error, data } = useQuery(GET_USERS);
if (error) return <h1>Something went wrong!</h1>;
if (loading) return <h1>Loading...</h1>;
return (
<main className="App">
<h1>Github | Users</h1>
{data.users.map((user) => (
<User key={user.id} user={user} />
))}
</main>
);
}
export default App;
يتلقى الخطاف useQuery الذي يوفره Apollo استعلام GraphQL ويعيد ثلاث حالات: loading (التحميل)، error (الخطأ)، و data (البيانات). إذا تم جلب البيانات بنجاح، نمررها إلى مكون User. وإلا، فإننا نعرض رسالة خطأ.
ملف App.js كاملاً
import React from "react";
import { useQuery } from "@apollo/react-hooks";
import gql from "graphql-tag";
import "./App.css";
const GET_USERS = gql`
{
users {
id
login
avatar_url
}
}
`;
const User = ({ user: { login, avatar_url } }) => (
<div className="Card">
<div>
<img alt="avatar" className="Card--avatar" src={avatar_url} />
<h1 className="Card--name">{login}</h1>
</div>
<a href={`https://github.com/${login}`} className="Card--link">
See profile
</a>
</div>
);
function App() {
const { loading, error, data } = useQuery(GET_USERS);
if (error) return <h1>Something went wrong!</h1>;
if (loading) return <h1>Loading...</h1>;
return (
<main className="App">
<h1>Github | Users</h1>
{data.users.map((user) => (
<User key={user.id} user={user} />
))}
</main>
);
}
export default App;
رائع! بهذا نكون قد انتهينا من بناء تطبيق Apollo GraphQL كامل المكدس باستخدام React و Node.js.

الخلاصة التقنية
لقد قدم هذا الدليل رحلة متكاملة في عالم تطوير تطبيقات Full-stack باستخدام Apollo GraphQL، React.js، و Node.js. لقد أظهرنا كيف يمكن لـ GraphQL تبسيط عملية جلب البيانات من خلال مخططات واضحة ومُحللات فعالة، مما يقلل من الحاجة إلى طلبات REST المتعددة ويزيد من كفاءة الاتصال بين العميل والخادم. استخدام Apollo Client في الواجهة الأمامية مع React Hooks يوفر تجربة تطوير سلسة وقوية لإدارة الحالة والتعامل مع البيانات غير المتزامنة. هذا النهج لا يعزز فقط أداء التطبيق وسهولة صيانته، بل يمنح المطورين أيضًا مرونة لا مثيل لها في بناء واجهات مستخدم تفاعلية وغنية بالبيانات. إن تبني هذه التقنيات يعني الاستثمار في مستقبل تطوير الويب، حيث الكفاءة والمرونة هما مفتاح النجاح.