كيف تبدء مع GraphQL و Apollo Client
Mohanad Alrwaihy
January 31, 2023
121
1
مقدمة للمبتدئين لكيفية أستخدام GraphQL و Apollo Client لمشاريع React
4 دقائق للقراءة
مقدمة عن GraphQL
ما هوا GraphQL 🤔
هيا لغة أستعلام او (Query Language) تستعمل للAPIs لأعطاء تفسير واضح للبيانات وأسترجاع بالضبط البيانات المرادة بأستخدام أستعلام واحد فقط.
لماذا نستعمل GraphQL 💭
لأنه يجعل من السهل تحديد البيانات المراد استعمالها من الAPIs.
الفرق بين GraphQL 🆚REST
الفرق الرئيسي بين GraphQL و REST هوا انه GraphQL لغة أستعلام مخصصة بينما REST هوا مفهوم معماري او عام للتطبيقات والبرامج القائمة على الشبكة.
في GraphQL تستطيع الحصول فقط على البيانات التي تريدها (لا أكثر ولا أقل). بينما في REST من ممكن ان الAPIs يسترجع لك الكثير من البيانات الغير هامة او العكس ان يسترجع لك عدد اقل من البيانات وتحتاج ان تقوم بالطلب مرة اخرى للحصول على كل البيانات.
الصورة من @NikkitaFTW
المشروع
صورة نهائية للمشروع 📷
لقد قمت ببناء برنامج للتبع القراءة بأستعمال GraphQL وتم استعمال Express.js للواجهة الخلفية (السيرفر) و React للواجهة العامة للمستخدم.
الواجهة الخلفية (السيرفر).
للواجهة الخلفية سنحدد الGraphQL Schema وهوا المخطط لنوع البيانات و سنوصل السيرفر لقاعدة بيانات بأستخدام MongoDB و Mongoose.
مخطط البيانات (Schema)
المخطط هوا التفسير لنوع البيانات في المشروع وعلاقتها مع بعضها البعض وكيف تظهر في النهاية.
انواع البيانات 📝
لدينا كتب (Books) وكتاب (ِauthors) كأنواع للبيانات والكود التالي يظهر لنا كيف ننشئ نوع البيانات هذه في مخطط البيانات (Schema) بأستعمال GraphQL وتحديد الحقول التي نريدها لكل نوع 👇
JAVASCRIPT//تحديد المعلومات الضرورية لكل كتاب
const BookType = new GraphQLObjectType({
name: 'Book',
fields: () => ({
id: { type: GraphQLID },
name: { type: GraphQLString },
genre: { type: GraphQLString },
author: {
type: AuthorType,
resolve(parent, args) {
//سنقوم بالبحث عن الكاتب من قاعدة البيانات (MongoDB)
return Author.findById(parent.authorid)
},
},
}),
})
//تحديد المعلومات الضرورية لكل كاتب
const AuthorType = new GraphQLObjectType({
name: 'Author',
fields: () => ({
id: { type: GraphQLID },
name: { type: GraphQLString },
age: { type: GraphQLInt },
books: {
type: new GraphQLList(BookType),
resolve(parent, args) {
//سنقوم بالبحث عن الكتب من قاعدة البيانات (MongoDB)
return Book.find({ authorid: parent.id })
},
},
}),
})الأستعلام الرئيسي (Root Query)
هوا نقطة البداية للرسم البياني وعن طريقه يتم تعريف كيفية أستخراج البيانات من GraphQL. لنفترض اننا نريد ان نستخرج أسماء كل الكتب وتصنيفها. في الRoot Query سيتم تعريف الأسم وماذا نريد ان نريد ان نستخرج منه.
JAVASCRIPT{
books {
name
genre
}
}هذا الأستعلام سيعمل على استدعاء اسماء الكتب كلها مع تصنيفاتها من قاعدة البيانات.
وهنا طريقة أنشاء الRoot Query وأنشاء حقل الكتب 👇
JAVASCRIPTconst RootQuery = new GraphQLObjectType({
name: 'RootQueryType',
fields: {
books: {
type: new GraphQLList(BookType),
return(parent, args) {
//استدعاء كل الكتب من قاعدة البيانات (MongoDB).
return Book.find({})
},
},
},
})المتغيرات (Mutation)
لأضافة كتب أو كتاب لقاعدة البيانات الخاصة بنا يجب ان نقوم بأنشاء Mutation وعن طريقه سيتم تعريف طريقة أضافة الكتب والكتاب لقاعدة البيانات
JAVASCRIPTconst Mutation = new GraphQLObjectType({
name: "Mutation",
fields: {
addAuthor: {
type: AuthorType,
args: {
name: { type: new GraphQLNonNull(GraphQLString) },
age: { type: new GraphQLNonNull(GraphQLInt) },
},
resolve(parent, args) {
//الكاتب هوا جزء من الAuthor Model من قاعدة البيانات MongoDB
let author = new Author({
name: args.name,
age: args.age,
})
//حفظ الكاتب في قاعدة البيانات (MongoDB).
return author.save()
},
}
}
}
})عندما نريد ان نغير بعض البيانات نقوم بعملها بالطريقة هذه في GraphQL:
JAVASCRIPTmutation {
addAuthor(name: "John Doe", age: 35) {
name
age
}
}مكتبة Apollo Client
في واجهة المستخدم سنقوم بأستخدام Apollo Client لنربط التطبيق بالسيرفر ولعمل ذلك لدينا خطوتين علينا القيام بها في ملف الapp.js
- علينا استدعاء Apollo Client وأستخدامه في ربط التطبيق في السيرفر بأعطائه
الuriلنقطة النهاية (endpoint) في GraphQL وبعمل ذلك سنقوم بتعليم Apollo انه سيتم طلب البيانات من هذه النقطةgraphql/ - علينا استدعاء Apollo Provider وتغليف تطبيق React به لأستقبال اي بيانات قادمة من السيرفر لتطبيقنا.
JAVASCRIPTimport ApolloClient from 'apollo-boost'
import { ApolloProvider } from 'react-apollo'
const client = new ApolloClient({
uri: 'http://localhost:5500/graphql',
})
function App() {
return (
<ApolloProvider client={client}>
<div className='App'>
<h1>Hello Apollo!</h1>
</div>
</ApolloProvider>
)
}
الأستعلامات (Queries)
لأنشاء أستعلام في واجهة المستخدم سنقوم بأستعمال مكتبة ApolloClient.
وأخذ الgql من مكتبة apollo-boost ليمكننا من أنشاء استعلامات خاصة لأستدعاء البيانات. على سبيل المثال لأستدعاء جميع الكتب وأضافة كتب الى قاعدة البيانات 👇
JAVASCRIPTimport { gql } from 'apollo-boost'
const getBooksQuery = gql`
{
books {
name
id
}
}
`
const addBookMutation = gql`
mutation ($name: String!, $genre: String!, $authorid: ID!) {
addBook(name: $name, genre: $genre, authorid: $authorid) {
name
id
}
}
`لأضافة كتب الى قاعدة البيانات علينا بأعطاء أسم الكتاب وتصنيفه و رقم المعرف الخاص بالكاتب authorid للمتغير هذا السبب ان الMutation تحتاج الى مدخلات.
أستعمال useQuery:
لأستدعاء البيانات من السيرفر بأستخدام أستعلام سوف نقوم بأستعمال الHook الخاصة useQuery.
JAVASCRIPTimport { Query } from 'react-apollo'
import { getBooksQuery } from '../queries/queries'
function BookList() {
return (
//The query getBooksQuery is the query we created above.
<Query query={getBooksQuery}>
{({ loading, error, data }) => {
if (loading) return <p>Loading...</p>
if (error) return <p>Error 😢</p>
return (
<ul className='book-list'>
{data.books.map(({ name, id }) => {
return <li key={id}>{name}</li>
})}
</ul>
)
}}
</Query>
)
}
أستعمال useMutation ⚓
لأضافة كتاب الى قاعدة البيانات سنقوم بأستعمال الHook الخاصة useMutation.
عندما يقوم المستخدم بأعطاء معلومات الكتاب ستقوم الدالة onSubmit(data, addBook) اللتي تستقبل معلومات الكتاب من المستخدم و addBook وهيا الدالة الخاصة من المتغير الذي أنشأناه مسبقا واذا اردنا تمرير هذه المعلومات وحفظها علينا بتمرير الdata الى دالة addBook.
وهنا كيف نفعل ذلك 👇
JAVASCRIPTimport { Mutation } from 'react-apollo'
import { addBookMutation } from '../queries/queries'
function addBook() {
const onSubmit = (data, addBook) => {
addBook({
variables: {
name: data.bookName,
genre: data.genre,
authorid: data.authorid,
},
refetchQueries: [{ query: getBooksQuery }],
})
}
return (
//This is the same addBookMutation that we created above.
<Mutation mutation={addBookMutation}>
{(addBook, { data }) => (
<form onSubmit={handleSubmit((data) => onSubmit(data, addBook))}>
<input
placeholder='Book Name 📕'
{...register('bookName', { required: true })}
/>
<input
placeholder='Genre 🌀'
{...register('genre', { required: true })}
/>
<select {...register('authorid')}>
{' '}
<option>Select the Author ✒</option>
{options()}
</select>
<input type='submit' value='Add Book 📕' />
</form>
)}
</Mutation>
)
}المصادر
الأدوات ⚙️
تم أستعمال هذه الأدوات في بناء الواجهة الخلفية (السيرفر):
للواجهة الأمامية تم أستعمال هذه الأدوات:
- React - تم أستعمال Vite لبناء تطبيق React
- Apollo Client - Apollo client هوا الحلقة التي توصل بين الواجهة الأمامية والخلفية وتستعمل لأتصال GraphQL ب React للقيام بعمليات البحث والتعديل.
لقواعد البيانات:

