GraphQL API مع TypeScript: دليل تعليمي خطوة بخطوة
GraphQL هي لغة استعلام لواجهات API تتيح للعملاء طلب البيانات التي يحتاجونها فقط. عند دمجها مع TypeScript، تساعد الكتابة الثابتة في تجنب الأخطاء أثناء مرحلة التطوير وتجعل الكود أكثر قابلية للتنبؤ. في هذا الدليل التعليمي، سننشئ GraphQL API كامل باستخدام Apollo Server و TypeScript.
سنشرح: إعداد المشروع، تعريف المخطط والأنواع، تنفيذ resolvers، عمليات التعديل (mutations) لتغيير البيانات، والتكامل مع قاعدة بيانات (in-memory للتبسيط). في نهاية المقال، ستتمكن من تشغيل خادم GraphQL خاص بك.
1. تحضير المشروع وتثبيت التبعيات
أولاً، سننشئ مشروع Node.js جديد ونثبت الحزم اللازمة.
mkdir graphql-typescript-tutorialcd graphql-typescript-tutorialnpm init -ynpm install apollo-server graphqlnpm install -D typescript @types/node ts-node nodemonسننشئ ملف tsconfig.json:
{ "compilerOptions": { "target": "ES2020", "module": "commonjs", "rootDir": "./src", "outDir": "./dist", "strict": true, "esModuleInterop": true, "skipLibCheck": true }, "include": ["src/**/*"]}سيكون هيكل المشروع كالتالي:
src/index.ts— نقطة الدخولsrc/schema.ts— مخطط GraphQLsrc/resolvers.ts— resolverssrc/types.ts— أنواع TypeScript
2. تعريف الأنواع ومخطط GraphQL
مخطط GraphQL يصف البيانات المتاحة وكيفية طلبها. كمثال، سننشئ نظامًا بسيطًا لإدارة المستخدمين والمقالات.
سننشئ src/types.ts:
export interface User { id: number; name: string; email: string;}
export interface Post { id: number; title: string; content: string; authorId: number;}
export interface CreateUserInput { name: string; email: string;}
export interface CreatePostInput { title: string; content: string; authorId: number;}الآن سننشئ src/schema.ts مع تعريف أنواع GraphQL:
import { gql } from 'apollo-server';
export const typeDefs = gql` type User { id: ID! name: String! email: String! posts: [Post!]! }
type Post { id: ID! title: String! content: String! author: User! }
input CreateUserInput { name: String! email: String! }
input CreatePostInput { title: String! content: String! authorId: ID! }
type Query { users: [User!]! user(id: ID!): User posts: [Post!]! post(id: ID!): Post }
type Mutation { createUser(input: CreateUserInput!): User! createPost(input: CreatePostInput!): Post! }`;لاحظ: نستخدم أنواع input لعمليات التعديل (mutations) — هذه ممارسة قياسية في GraphQL.
3. تنفيذ resolvers باستخدام TypeScript
Resolvers هي دوال تُرجع البيانات لكل حقل في المخطط. سننشئ src/resolvers.ts:
import { User, Post, CreateUserInput, CreatePostInput } from './types';
// قاعدة بيانات in-memorylet users: User[] = [ { id: 1, name: 'Alice', email: 'alice@example.com' }, { id: 2, name: 'Bob', email: 'bob@example.com' },];
let posts: Post[] = [ { id: 1, title: 'GraphQL Basics', content: '...', authorId: 1 }, { id: 2, title: 'TypeScript Guide', content: '...', authorId: 2 },];
let nextUserId = 3;let nextPostId = 3;
export const resolvers = { Query: { users: (): User[] => users, user: (_: unknown, args: { id: string }): User | undefined => users.find(u => u.id === Number(args.id)), posts: (): Post[] => posts, post: (_: unknown,