في تطوير الويب، تحسين التطبيقات وتوسيعها كان دائمًا مشكلة. حقق React.js نجاحًا استثنائيًا في تطوير واجهات المستخدم في الجزء الأمامي كأداة، مما يوفر طريقة قوية لإنشاء واجهات مستخدم. ومع تعقيد الأمور في التطبيقات المتنامية، خاصة عندما يتعلق الأمر بنقاط نهاية API REST متعددة. قد تكون القلق من الجلب الزائد، حيث يتطلب البيانات الزائدة، مصدرًا لعقبات الأداء وتجربة مستخدم سيئة.
من بين الحلول لهذه التحديات هو اعتماد استخدام GraphQL مع تطبيقات React. إذا كان لديك نقاط نهاية REST متعددة في الجزء الخلفي، فإن إدخال طبقة GraphQL التي تستدعي نقاط نهاية API REST الخاصة بك داخليًا يمكن أن يعزز تطبيقك من الجلب الزائد ويوحد تطبيقك في الجزء الأمامي. في هذه المقالة، ستجد كيفية استخدامها، ومزايا وعيوب هذا النهج، والتحديات المختلفة، وكيفية التعامل معها. سننغمس أيضًا بعمق في بعض الأمثلة العملية على كيفية يمكن لـ GraphQL مساعدتك في تحسين الطرق التي تعمل بها مع بياناتك.
الجلب الزائد في واجهات برمجة التطبيقات REST
يحدث الجلب الزائد في واجهات برمجة التطبيقات REST عندما يكون حجم البيانات التي يقدمها الAPI للعميل أكثر مما يحتاجه العميل. وهذه مشكلة شائعة في واجهات برمجة التطبيقات REST، التي تعود عادةً ما تعيد كائنًا ثابتًا أو مخطط استجابة. لفهم هذه المشكلة بشكل أفضل، دعونا نأخذ مثالًا.
لنفترض صفحة ملف تعريف المستخدم حيث يكون من الضروري فقط عرض الاسم
والبريد الإلكتروني
للمستخدم. باستخدام API REST نموذجي، قد يبدو جلب بيانات المستخدم مثل هذا:
fetch('/api/users/1')
.then(response => response.json())
.then(user => {
// Use the user's name and profilePicture in the UI
});
ستتضمن استجابة الAPI بيانات غير ضرورية:
{
"id": 1,
"name": "John Doe",
"profilePicture": "/images/john.jpg",
"email": "[email protected]",
"address": "123 Denver St",
"phone": "111-555-1234",
"preferences": {
"newsletter": true,
"notifications": true
},
// ...more details
}
على الرغم من أن التطبيق يتطلب فقط حقلي الاسم والبريد الإلكتروني للمستخدم، إلا أن واجهة برمجة التطبيقات (API) تعيد كائن المستخدم بالكامل. غالبًا ما تؤدي هذه البيانات الإضافية إلى زيادة حجم الحمولة، مما يتطلب نطاقًا تردديًا أكبر، وقد تؤدي في النهاية إلى إبطاء التطبيق عند استخدامه على جهاز ذو موارد محدودة أو اتصال شبكة بطيء.
GraphQL كحل
تعالج GraphQL مشكلة التحميل الزائد من خلال السماح للعملاء بطلب البيانات التي يحتاجونها بالضبط. من خلال دمج خادم GraphQL في تطبيقك، يمكنك إنشاء طبقة مرنة وفعالة لجلب البيانات تتواصل مع واجهات برمجة التطبيقات REST الحالية لديك.
كيف يعمل
1. إعداد خادم GraphQL
تقدم خادم GraphQL الذي يعمل كوسيط بين واجهة React الأمامية وواجهات برمجة التطبيقات REST.
2. تعريف المخطط
تحدد مخطط GraphQL الذي يحدد أنواع البيانات والاستعلامات التي يحتاجها واجهتك الأمامية.
3. تنفيذ المحللات
تنفذ محللات في خادم GraphQL تقوم بجلب البيانات من واجهات برمجة التطبيقات REST وإرجاع الحقول الضرورية فقط.
4. تكامل الواجهة الأمامية
تقوم بتحديث تطبيق React الخاص بك لاستخدام استعلامات GraphQL بدلاً من استدعاءات واجهة برمجة التطبيقات REST المباشرة.
تتيح لك هذه الطريقة تحسين جلب البيانات دون الحاجة إلى إعادة هيكلة البنية التحتية الخلفية الحالية لديك.
تنفيذ GraphQL في تطبيق React
لنلقِ نظرة على كيفية إعداد خادم GraphQL ودمجه في تطبيق React.
تثبيت الاعتماديات
npm install apollo-server graphql axios
تعريف النموذج
أنشئ ملفًا يسمى schema.js
:
const { gql } = require('apollo-server');
const typeDefs = gql`
type User {
id: ID!
name: String
email: String // Ensure this matches exactly with the frontend query
}
type Query {
user(id: ID!): User
}
`;
module.exports = typeDefs;
يحدد هذا النموذج نوع User
واستعلام user
الذي يُحضر مستخدمًا حسب الهوية.
تنفيذ المُحللون
أنشئ ملفًا يسمى resolvers.js
:
const resolvers = {
Query: {
user: async (_, { id }) => {
try {
const response = await fetch(`https://jsonplaceholder.typicode.com/users/${id}`);
const user = await response.json();
return {
id: user.id,
name: user.name,
email: user.email, // Return email instead of profilePicture
};
} catch (error) {
throw new Error(`Failed to fetch user: ${error.message}`);
}
},
},
};
module.exports = resolvers;
يُحضر مُحلل الاستعلام user
البيانات من واجهة برمجة التطبيقات REST API ويُرجع فقط الحقول المطلوبة.
سنستخدم https://jsonplaceholder.typicode.com/ لواجهة برمجة التطبيقات REST API الوهمية الخاصة بنا.
إعداد الخادم
أنشئ ملفًا server.js
:
const { ApolloServer } = require('apollo-server');
const typeDefs = require('./schema');
const resolvers = require('./resolvers');
const server = new ApolloServer({
typeDefs,
resolvers,
});
server.listen({ port: 4000 }).then(({ url }) => {
console.log(`GraphQL Server ready at ${url}`);
});
قم بتشغيل الخادم:
node server.js
خادم GraphQL الخاص بك نشط على http://localhost:4000/graphql، وإذا قمت بتشغيل استعلام لخادمك، سيوجهك إلى هذه الصفحة.
التكامل مع تطبيق React
سنقوم الآن بتغيير تطبيق React لاستخدام واجهة برمجة التطبيقات GraphQL.
تثبيت عميل Apollo
npm install @apollo/client graphql
تكوين عميل Apollo
import { ApolloClient, InMemoryCache } from '@apollo/client';
const client = new ApolloClient({
uri: 'http://localhost:4000',
cache: new InMemoryCache(),
});
كتابة الاستعلام GraphQL
const GET_USER = gql`
query GetUser($id: ID!) {
user(id: $id) {
id
name
email
}
}
`;
الآن، قم بدمج قطع الشفرة أعلاه مع تطبيق React الخاص بك. فيما يلي تطبيق React بسيط يتيح لمستخدم اختيار هوية المستخدم وعرض المعلومات:
import { useState } from 'react';
import { ApolloClient, InMemoryCache, ApolloProvider, gql, useQuery } from '@apollo/client';
import './App.css'; // Link to the updated CSS
const client = new ApolloClient({
uri: 'http://localhost:4000', // Ensure this is the correct URL for your GraphQL server
cache: new InMemoryCache(),
});
const GET_USER = gql`
query GetUser($id: ID!) {
user(id: $id) {
id
name
email
}
}
`;
const User = ({ userId }) => {
const { loading, error, data } = useQuery(GET_USER, {
variables: { id: userId },
});
if (loading) return <p>Loading</p>;
if (error) return <p>Error: {error.message}</p>;
return (
<div className="user-container">
<h2>{data.user.name}</h2>
<p>Email: {data.user.email}</p>
</div>
);
};
const App = () => {
const [selectedUserId, setSelectedUserId] = useState("1");
return (
<ApolloProvider client={client}>
<div className="app-container">
<h1 className="title">GraphQL User Lookup</h1>
<div className="dropdown-container">
<label htmlFor="userSelect">Select User ID:</label>
<select
id="userSelect"
value={selectedUserId}
onChange={(e) => setSelectedUserId(e.target.value)}
>
{Array.from({ length: 10 }, (_, index) => (
<option key={index + 1} value={index + 1}>
{index + 1}
</option>
))}
</select>
</div>
<User userId={selectedUserId} />
</div>
</ApolloProvider>
);
};
export default App;
النتيجة
سترى تفاصيل مستخدم بسيطة مثل هذه: [رابط جيت هاب].
العمل مع نقاط النهاية المتعددة
تخيل سيناريو حيث تحتاج إلى استرجاع منشورات مستخدم معين، جنبًا إلى جنب مع التعليقات الفردية على كل منشور. بدلاً من إجراء ثلاث مكالمات API منفصلة من تطبيق React الخاص بك والتعامل مع بيانات غير ضرورية، يمكنك تبسيط العملية باستخدام GraphQL. من خلال تعريف مخطط وصياغة استعلام GraphQL، يمكنك طلب فقط البيانات الدقيقة التي يحتاجها واجهة المستخدم الخاصة بك، مما يجعل الطلب فعالاً في مكان واحد.
نحتاج إلى جلب بيانات المستخدم، منشوراتهم، والتعليقات على كل منشور من نقاط النهاية المختلفة. سنستخدم fetch لجمع البيانات من نقاط النهاية المتعددة وإرجاعها عبر GraphQL.
تحديث المحللات
const fetch = require('node-fetch');
const resolvers = {
Query: {
user: async (_, { id }) => {
try {
// fetch user
const userResponse = await fetch(`https://jsonplaceholder.typicode.com/users/${id}`);
const user = await userResponse.json();
// fetch posts for a user
const postsResponse = await fetch(`https://jsonplaceholder.typicode.com/posts?userId=${id}`);
const posts = await postsResponse.json();
// fetch comments for a post
const postsWithComments = await Promise.all(
posts.map(async (post) => {
const commentsResponse = await fetch(`https://jsonplaceholder.typicode.com/comments?postId=${post.id}`);
const comments = await commentsResponse.json();
return { post, comments };
})
);
return {
id: user.id,
name: user.name,
email: user.email,
posts: postsWithComments,
};
} catch (error) {
throw new Error(`Failed to fetch user data: ${error.message}`);
}
},
},
};
module.exports = resolvers;
تحديث مخطط GraphQL
const { gql } = require('apollo-server');
const typeDefs = gql`
type Comment {
id: ID!
name: String
email: String
body: String
}
type Post {
id: ID!
title: String
body: String
comments: [Comment]
}
type User {
id: ID!
name: String
email: String
posts: [Post]
}
type Query {
user(id: ID!): User
}
`;
module.exports = typeDefs;
تظل إعدادات الخادم في server.js
كما هي. بمجرد تحديث كود React.js، نحصل على الناتج أدناه:
النتيجة
سترى مستخدمًا مفصلًا مثل هذا: [رابط جيت هاب].
فوائد هذه الطريقة
توفير GraphQL في تطبيق React الخاص بك يقدم عدة مزايا:
القضاء على الإفراط في الجلب
ميزة رئيسية في GraphQL هي أنها تجلب فقط ما تطلبه بالضبط. الخادم يُرجع فقط الحقول المطلوبة ويضمن تقليل كمية البيانات المنقولة عبر الشبكة من خلال تقديم فقط ما تتطلبه الاستعلام، مما يحسن الأداء.
تبسيط كود الواجهة الأمامية
يتيح لك GraphQL الحصول على المعلومات اللازمة في استعلام واحد بغض النظر عن مصدرها. داخليًا، قد يقوم بعمل 3 استدعاءات API للحصول على المعلومات. يساعد ذلك في تبسيط كود الواجهة الأمامية لديك لأنه لم يعد عليك تنسيق طلبات غير متزامنة مختلفة ودمج نتائجها.
تحسين تجربة المطورين
يوفر النوع القوي واستكشاف المخطط أدوات أفضل وفحص أخطاء أكثر من تنفيذ API التقليدي. علاوة على ذلك، هناك بيئات تفاعلية حيث يمكن للمطورين بناء واختبار الاستعلامات، بما في ذلك GraphiQL أو Apollo Explorer.
معالجة التعقيدات والتحديات
تقدم هذه الطريقة بعض المزايا ولكنها أيضًا تقدم بعض التحديات التي يجب إدارتها.
طبقة إضافية من الخلفية
إن إدخال خادم GraphQL يخلق طبقة إضافية في بنية خلفيتك، وإذا لم يتم إدارتها بشكل صحيح، فإنها تصبح نقطة فشل واحدة.
الحل
انتبه إلى معالجة الأخطاء والمراقبة. يمكن أن تساعد أدوات الحاويات والتنسيق مثل Docker وKubernetes في إدارة القابلية للتوسع والموثوقية.
زيادة محتملة في الأداء
قد يقوم خادم GraphQL بعمل عدة استدعاءات REST API لحل استعلام واحد، مما قد يقدم تأخيرًا وزيادة في الحمل على النظام.
الحل
قم بتخزين النتائج مؤقتًا لتجنب إجراء عدة استدعاءات إلى API. بعض الأدوات، مثل DataLoader، يمكن أن تتعامل مع عملية تجميع وتخزين الطلبات مؤقتًا.
الخاتمة
“البساطة هي أقصى درجات الفخامة” — ليوناردو دا فينشي
دمج GraphQL في تطبيق React الخاص بك ليس مجرد تحسين أداء — بل هو خطوة استراتيجية نحو بناء تطبيقات أكثر صيانة وتوسعًا وكفاءة. من خلال التعامل مع مشكلة الجلب الزائد وتبسيط إدارة البيانات، لن تعزز فقط تجربة المستخدم بل ستمنح فريق التطوير الخاص بك أدوات وممارسات أفضل.
على الرغم من أن إدخال طبقة GraphQL يأتي مع مجموعة من التحديات الخاصة به، إلا أن الفوائد غالبا ما تتفوق على التعقيدات. من خلال التخطيط بعناية لتنفيذك، وتحسين محلليك، وتأمين النقاط النهائية الخاصة بك، يمكنك التخفيف من العيوب المحتملة. علاوة على ذلك، القابلية التي يوفرها GraphQL يمكن أن تضمن لتطبيقك مواكبة التطور والنمو.
اعتناق GraphQL لا يعني التخلي عن واجهات برمجة التطبيقات القائمة لديك. بل يتيح لك الاستفادة من نقاط قوتها بينما يوفر طبقة وصول للبيانات أكثر كفاءة ومرونة لتطبيقات الواجهة الأمامية الخاصة بك. هذا النهج الهجين يجمع بين موثوقية REST ورشاقة GraphQL، مما يمنحك أفضل العوالم.
إذا كنت مستعدًا لرفع تطبيق React الخاص بك إلى المستوى التالي، فكر في دمج GraphQL في استراتيجية جلب البيانات الخاصة بك. قد تواجه التحديات في هذه الرحلة، ولكن المكافآت — عملية تطوير أكثر سلاسة، مطورين أكثر سعادة، ومستخدمين راضين — تجعلها جهداً جديرًا بالمضي قدمًا.
الشفرة الكاملة متوفرة
يمكنك العثور على الكود الكامل لهذا التنفيذ على مستودعي GitHub.
Source:
https://dzone.com/articles/enhancing-react-applications-with-graphql-over-rest-apis