مقدمة إلى GraphQL API مع TypeScript
GraphQL هي لغة استعلام لواجهة API الخاصة بك، تتيح للعملاء طلب البيانات التي يحتاجونها فقط. وبالاقتران مع TypeScript، تحصل على كتابة صارمة للأنواع، وإكمال تلقائي في بيئة التطوير المتكاملة (IDE)، وأخطاء أقل في مرحلة التجميع. في هذا الدليل العملي، سننشئ GraphQL API كامل من الصفر باستخدام TypeScript و Apollo Server.
هذا الدليل مناسب للمطورين الملمين بأساسيات JavaScript و Node.js. سننتقل من تثبيت التبعيات إلى اختبار API الجاهز.
1. إعداد المشروع وتثبيت التبعيات
أولاً، سننشئ مشروعاً جديداً ونثبت الحزم اللازمة. افتح الطرفية ونفذ:
mkdir graphql-ts-tutorialcd graphql-ts-tutorialnpm init -yقم بتثبيت TypeScript و Apollo Server و GraphQL:
npm install apollo-server graphqlnpm install -D typescript @types/node ts-node nodemonأنشئ ملف tsconfig.json لتكوين TypeScript:
{ "compilerOptions": { "target": "ES2020", "module": "commonjs", "rootDir": "./src", "outDir": "./dist", "strict": true, "esModuleInterop": true, "skipLibCheck": true }, "include": ["src/**/*"]}أنشئ مجلد src وملف src/index.ts - سيكون هذا نقطة الدخول إلى تطبيقنا.
2. إنشاء مخطط GraphQL وأنواع TypeScript
في GraphQL، يحدد المخطط أنواع البيانات والعمليات المتاحة للعميل. لننشئ مخططاً بسيطاً لإدارة الكتب.
ملف src/schema.ts:
import { gql } from 'apollo-server';
export const typeDefs = gql` type Book { id: ID! title: String! author: String! publishedYear: Int }
type Query { books: [Book] book(id: ID!): Book }
type Mutation { addBook(title: String!, author: String!, publishedYear: Int): Book deleteBook(id: ID!): Book }`;الآن، دعنا نحدد واجهات TypeScript لبياناتنا. أنشئ src/types.ts:
export interface Book { id: string; title: string; author: string; publishedYear?: number;}لاحظ: واجهات TypeScript ضرورية للمنطق الداخلي، بينما أنواع GraphQL مخصصة للتفاعل بين العميل والخادم. يجب أن تكون متوافقة.
3. تنفيذ المحللات والخادم
المحللات هي دوال تُرجع البيانات لكل حقل في المخطط. لننشئ ملف src/resolvers.ts مع محاكاة لقاعدة البيانات:
import { Book } from './types';
let books: Book[] = [ { id: '1', title: 'الحرب والسلام', author: 'ليو تولستوي', publishedYear: 1869 }, { id: '2', title: 'الجريمة والعقاب', author: 'فيودور دوستويفسكي', publishedYear: 1866 },];
export const resolvers = { Query: { books: (): Book[] => books, book: (_: any, args: { id: string }): Book | undefined => { return books.find(book => book.id === args.id); }, }, Mutation: { addBook: (_: any, args: { title: string; author: string; publishedYear?: number }): Book => { const newBook: Book = { id: String(books.length + 1), title: args.title, author: args.author, publishedYear: args.publishedYear, }; books.push(newBook); return newBook; }, deleteBook: (_: any, args: { id: string }): Book | null => { const index = books.findIndex(book => book.id === args.id); if (index === -1) return null; const deletedBook = books.splice(index, 1)[0]; return deletedBook; }, },};الآن، دعنا نربط كل شيء في الملف الرئيسي src/index.ts:
import { ApolloServer } from 'apollo-server';import { typeDefs } from './schema';import { r