واجهات GraphQL

إعداد Apollo Server

20 دقيقة الدرس 5 من 35

مقدمة إلى Apollo Server

Apollo Server هو أحد أشهر تطبيقات خادم GraphQL لـ Node.js. يوفر خادم GraphQL جاهزاً للإنتاج ومتوافقاً مع المواصفات يعمل مع أي مخطط GraphQL. من السهل إعداد Apollo Server، وعالي الأداء، ويأتي مع ميزات مدمجة مثل معالجة الأخطاء والمقاييس وتكامل Apollo Studio.

الفوائد الرئيسية: يتكامل Apollo Server بسلاسة مع أطر Node.js الشهيرة (Express، Fastify، Koa)، ويوفر دعماً ممتازاً لـ TypeScript، ويتضمن أدوات مطور قوية.

التثبيت

أولاً، أنشئ مشروع Node.js جديداً وقم بتثبيت التبعيات المطلوبة:

# إنشاء دليل المشروع mkdir graphql-server cd graphql-server # تهيئة مشروع Node.js npm init -y # تثبيت Apollo Server و GraphQL npm install @apollo/server graphql # تثبيت nodemon للتطوير (اختياري) npm install --save-dev nodemon

حدّث package.json الخاص بك باستخدام نص بدء:

{ "name": "graphql-server", "version": "1.0.0", "type": "module", "scripts": { "start": "node index.js", "dev": "nodemon index.js" }, "dependencies": { "@apollo/server": "^4.10.0", "graphql": "^16.8.1" }, "devDependencies": { "nodemon": "^3.0.2" } }
ملاحظة: يتيح تعيين "type": "module" استخدام استيرادات ES6 بدلاً من عبارات require في CommonJS.

إنشاء خادم Apollo الأول

أنشئ ملف index.js بإعداد Apollo Server الأساسي:

import { ApolloServer } from '@apollo/server'; import { startStandaloneServer } from '@apollo/server/standalone'; // تعريف مخطط GraphQL الخاص بك const typeDefs = `#graphql type Book { title: String! author: String! year: Int! } type Query { books: [Book!]! book(title: String!): Book } `; // بيانات عينة const books = [ { title: 'The Awakening', author: 'Kate Chopin', year: 1899 }, { title: 'City of Glass', author: 'Paul Auster', year: 1985 }, { title: 'أولاد حارتنا', author: 'نجيب محفوظ', year: 1959 } ]; // تعريف المحللات const resolvers = { Query: { books: () => books, book: (parent, args) => { return books.find(book => book.title === args.title); } } }; // إنشاء نسخة Apollo Server const server = new ApolloServer({ typeDefs, resolvers, }); // بدء الخادم const { url } = await startStandaloneServer(server, { listen: { port: 4000 }, }); console.log(`🚀 الخادم جاهز على ${url}`);

فهم تعريف المخطط

يحتوي السلسلة النصية typeDefs على مخطط GraphQL الخاص بك باستخدام لغة تعريف المخطط (SDL):

const typeDefs = `#graphql # التعليق #graphql يمكّن تمييز بناء الجملة # تعريف نوع مخصص type Book { title: String! # سلسلة نصية غير قابلة للقيمة الفارغة author: String! year: Int! # عدد صحيح غير قابل للقيمة الفارغة } # تعريف الاستعلامات المتاحة type Query { books: [Book!]! # يُرجع مصفوفة غير فارغة من كتب غير فارغة book(title: String!): Book # يأخذ وسيط العنوان، يُرجع كتاباً قابلاً للقيمة الفارغة } `;
مهم: يمكّن التعليق #graphql في بداية القالب الحرفي تمييز بناء جملة GraphQL في المحررات مع تثبيت ملحقات GraphQL.

كتابة المحللات

المحللات هي دوال تتعامل مع منطق جلب البيانات لكل حقل في مخططك:

const resolvers = { Query: { // محلل لاستعلام الكتب books: () => { // إرجاع جميع الكتب return books; }, // محلل لاستعلام الكتاب مع الوسائط book: (parent, args, context, info) => { // args يحتوي على الوسائط الممررة إلى الاستعلام return books.find(book => book.title === args.title); } } };

معاملات دالة المحلل:

  • parent: نتيجة المحلل الأصلي (مفيد للمحللات المتداخلة)
  • args: الوسائط الممررة إلى الحقل في الاستعلام
  • context: كائن مشترك عبر جميع المحللات (مفيد للمصادقة، واتصالات قاعدة البيانات)
  • info: معلومات حول حالة تنفيذ الاستعلام

بدء الخادم

قم بتشغيل الخادم الخاص بك باستخدام أحد هذه الأوامر:

# وضع الإنتاج npm start # وضع التطوير مع إعادة التحميل التلقائي npm run dev

يجب أن تشاهد الرسالة:

🚀 الخادم جاهز على http://localhost:4000/

استخدام Apollo Sandbox

يوفر Apollo Server تلقائياً Apollo Sandbox، وهو IDE GraphQL قوي. افتح متصفحك وانتقل إلى http://localhost:4000/.

جرب هذه الاستعلامات: في Apollo Sandbox، اختبر خادمك باستخدام هذه الاستعلامات النموذجية.
# الاستعلام 1: الحصول على جميع الكتب query GetAllBooks { books { title author year } } # الاستعلام 2: الحصول على كتاب محدد query GetBook { book(title: "City of Glass") { title author year } } # الاستعلام 3: استخدام المتغيرات query GetBookByTitle($title: String!) { book(title: $title) { title author year } } # المتغيرات للاستعلام 3: { "title": "أولاد حارتنا" }

إضافة الطفرات

لنوسع مخططنا لدعم إنشاء كتب جديدة:

const typeDefs = `#graphql type Book { id: ID! title: String! author: String! year: Int! } input CreateBookInput { title: String! author: String! year: Int! } type Query { books: [Book!]! book(id: ID!): Book } type Mutation { createBook(input: CreateBookInput!): Book! deleteBook(id: ID!): Boolean! } `; // تحديث بنية البيانات بالمعرفات let books = [ { id: '1', title: 'The Awakening', author: 'Kate Chopin', year: 1899 }, { id: '2', title: 'City of Glass', author: 'Paul Auster', year: 1985 }, { id: '3', title: 'أولاد حارتنا', author: 'نجيب محفوظ', year: 1959 } ]; let nextId = 4; const resolvers = { Query: { books: () => books, book: (parent, args) => books.find(book => book.id === args.id) }, Mutation: { createBook: (parent, args) => { const newBook = { id: String(nextId++), ...args.input }; books.push(newBook); return newBook; }, deleteBook: (parent, args) => { const index = books.findIndex(book => book.id === args.id); if (index === -1) return false; books.splice(index, 1); return true; } } };

اختبار الطفرات

جرب هذه الأمثلة من الطفرات في Apollo Sandbox:

# إنشاء كتاب جديد mutation CreateBook { createBook(input: { title: "1984" author: "George Orwell" year: 1949 }) { id title author year } } # حذف كتاب mutation DeleteBook { deleteBook(id: "1") }

أفضل ممارسات بنية المشروع

مع نمو واجهة برمجة التطبيقات الخاصة بك، قم بتنظيم الكود الخاص بك في ملفات منفصلة:

graphql-server/ ├── src/ │ ├── schema/ │ │ ├── typeDefs.js # تعريفات المخطط │ │ └── resolvers.js # دوال المحلل │ ├── models/ │ │ └── book.js # نماذج البيانات │ ├── datasources/ │ │ └── bookAPI.js # منطق جلب البيانات │ └── utils/ │ └── helpers.js # دوال مساعدة ├── index.js # نقطة دخول الخادم └── package.json

مثال: فصل typeDefs والمحللات

// src/schema/typeDefs.js export const typeDefs = `#graphql type Book { id: ID! title: String! author: String! year: Int! } # ... بقية المخطط `; // src/schema/resolvers.js export const resolvers = { Query: { books: () => { /* ... */ }, book: (parent, args) => { /* ... */ } }, Mutation: { createBook: (parent, args) => { /* ... */ } } }; // index.js import { ApolloServer } from '@apollo/server'; import { startStandaloneServer } from '@apollo/server/standalone'; import { typeDefs } from './src/schema/typeDefs.js'; import { resolvers } from './src/schema/resolvers.js'; const server = new ApolloServer({ typeDefs, resolvers }); const { url } = await startStandaloneServer(server, { listen: { port: 4000 } }); console.log(`🚀 الخادم جاهز على ${url}`);

إضافة السياق

يتم مشاركة السياق عبر جميع المحللات وهو مفيد للمصادقة واتصالات قاعدة البيانات والمزيد:

const { url } = await startStandaloneServer(server, { listen: { port: 4000 }, context: async ({ req }) => { // الحصول على رمز المصادقة من الرؤوس const token = req.headers.authorization || ''; // إضافة معلومات المستخدم إلى السياق return { user: getUserFromToken(token), dataSources: { booksAPI: new BooksAPI() } }; } }); // استخدام السياق في المحللات const resolvers = { Query: { books: (parent, args, context) => { // الوصول إلى context.user للمصادقة if (!context.user) { throw new Error('غير مصادق'); } return context.dataSources.booksAPI.getAllBooks(); } } };
ملاحظة أمنية: قم دائماً بالتحقق من صحة إدخال المستخدم وتعقيمه في المحللات الخاصة بك. لا تثق أبداً ببيانات العميل دون التحقق من صحتها.

معالجة الأخطاء

يوفر Apollo Server معالجة أخطاء مدمجة. يمكنك طرح أخطاء في المحللات:

import { GraphQLError } from 'graphql'; const resolvers = { Query: { book: (parent, args) => { const book = books.find(b => b.id === args.id); if (!book) { throw new GraphQLError('الكتاب غير موجود', { extensions: { code: 'NOT_FOUND', argumentName: 'id' } }); } return book; } } };
تمرين: قم ببناء واجهة برمجة تطبيقات GraphQL بسيطة لنظام إدارة المهام:
  • أنشئ نوع Task مع حقول id وtitle وdescription وcompleted وcreatedAt
  • نفذ الاستعلامات: tasks، task(id)، completedTasks
  • نفذ الطفرات: createTask، updateTask، deleteTask، toggleTask
  • استخدم أنواع الإدخال لعمليات الإنشاء والتحديث
  • أضف معالجة أخطاء مناسبة لحالات عدم العثور
  • اختبر جميع العمليات في Apollo Sandbox

ملخص

في هذا الدرس، تعلمت كيفية إعداد Apollo Server وتحديد المخططات والمحللات ومعالجة الاستعلامات والطفرات وبناء مشروع GraphQL الخاص بك. يوفر Apollo Server أساساً ممتازاً لبناء واجهات برمجة تطبيقات GraphQL جاهزة للإنتاج. في الدروس التالية، سنستكشف موضوعات متقدمة مثل الاتصال بقواعد البيانات والمصادقة والاشتراكات وتحسين الأداء.