دليل المبتدئين لاستخدام graphql-codegen

Maurice Odida

Maurice Odida

20 يونيو 2025

دليل المبتدئين لاستخدام graphql-codegen

في المشهد المتطور باستمرار لتطوير الويب، برزت GraphQL كبديل قوي لواجهات برمجة التطبيقات التقليدية (REST APIs)، مقدمة للعملاء القدرة على طلب البيانات التي يحتاجونها بالضبط. ومع ذلك، يمكن لهذه المرونة أن تقدم مجموعة جديدة من التحديات، خاصة عندما يتعلق الأمر بالحفاظ على سلامة الأنواع (type safety) بين الواجهة الأمامية (frontend) والخلفية (backend). هنا يأتي دور graphql-codegen، أداة ثورية تعمل على أتمتة توليد الكود المكتوب بأنواع (typed code) من مخطط GraphQL الخاص بك، مما يعزز سير عمل التطوير الخاص بك ويقضي على فئة كاملة من أخطاء وقت التشغيل (runtime errors).

سيكون هذا المقال دليلك لفهم وإتقان graphql-codegen. سنبدأ بالمفاهيم الأساسية، ونتطرق إلى مثال عملي خطوة بخطوة لإعداد الأداة وتكوينها، ونستكشف أفضل الممارسات لدمجها في مشاريعك. بنهاية هذا الدليل، ستكون مجهزًا للاستفادة من graphql-codegen لبناء تطبيقات أكثر قوة وقابلية للصيانة وسلامة في الأنواع (type-safe).

💡
هل تريد أداة رائعة لاختبار واجهات برمجة التطبيقات (API Testing) تولد توثيقًا جميلًا لواجهات برمجة التطبيقات؟

هل تريد منصة متكاملة وشاملة لفريق المطورين الخاص بك للعمل معًا بأقصى إنتاجية؟

Apidog يلبي جميع متطلباتك، ويحل محل Postman بسعر أقل بكثير!
button

ما هو graphql-codegen ولماذا تحتاجه؟

في جوهره، graphql-codegen هو أداة سطر أوامر تقوم بفحص مخطط GraphQL الخاص بك وعمليات GraphQL الخاصة بك (الاستعلامات queries، الطفرات mutations، والاشتراكات subscriptions) وتوليد كود بمجموعة متنوعة من اللغات. لغرض هذا الدليل للمبتدئين، سنركز على حالة الاستخدام الأكثر شيوعًا: توليد أنواع TypeScript وخطافات (hooks) لتطبيقات الواجهة الأمامية.

المشكلة الأساسية التي يحلها graphql-codegen هي عملية كتابة واجهات TypeScript يدويًا لهياكل بيانات واجهة برمجة تطبيقات GraphQL الخاصة بك ونتائج استعلاماتك، وهي عملية مملة وعرضة للأخطاء. بدونه، يُترك المطورون إما للعمل ببيانات غير مكتوبة (مما يفقد فوائد TypeScript) أو يقضون وقتًا طويلًا في إنشاء وصيانة أنواع يمكن أن تصبح قديمة بسهولة مع تطور واجهة برمجة التطبيقات.

فوائد تبني graphql-codegen متعددة:

يتوافق هذا النهج تمامًا مع فلسفة التطوير "schema-first" (المخطط أولاً)، حيث يعمل مخطط GraphQL كمصدر وحيد للحقيقة لواجهة برمجة التطبيقات الخاصة بك.

البدء: إعدادك الأول لـ graphql-codegen

دعنا نتعمق في الجوانب العملية لاستخدام graphql-codegen. لهذا البرنامج التعليمي، سنفترض أن لديك فهمًا أساسيًا لـ GraphQL وTypeScript، وأن لديك Node.js ومدير حزم (مثل npm أو yarn) مثبتين.

هدفنا هو إعداد graphql-codegen لتطبيق React بسيط يعرض قائمة بمنشورات المدونة.

الخطوة 1: تهيئة المشروع والتبعيات

أولاً، دعنا ننشئ مشروع React جديدًا باستخدام TypeScript ونثبت التبعيات اللازمة.Bash

npx create-react-app my-blog --template typescript
cd my-blog
npm install @apollo/client graphql
npm install -D @graphql-codegen/cli @graphql-codegen/client-preset typescript

فيما يلي تفصيل للتبعيات التي قمنا بتثبيتها:

الخطوة 2: معالج تهيئة graphql-codegen

أسهل طريقة للبدء مع graphql-codegen هي باستخدام معالج التهيئة الخاص به. قم بتشغيل الأمر التالي في الدليل الجذر لمشروعك:Bash

npx graphql-codegen init

سيطلب منك المعالج سلسلة من الأسئلة للمساعدة في تكوين مشروعك. فيما يلي مجموعة نموذجية من الإجابات لسيناريو تطبيق المدونة الخاص بنا:

بعد الإجابة على هذه الأسئلة، سيقوم المعالج بإنشاء ملف codegen.ts في الدليل الجذر لمشروعك وإضافة سكريبت codegen إلى ملف package.json الخاص بك.

الخطوة 3: فهم ملف التكوين (codegen.ts)

ملف codegen.ts هو قلب إعداد graphql-codegen الخاص بك. دعنا نلقي نظرة على نسخة مبسطة مما يولده المعالج:TypeScript

import type { CodegenConfig } from '@graphql-codegen/cli';

const config: CodegenConfig = {
  overwrite: true,
  schema: "https://swapi-graphql.netlify.app/.netlify/functions/index",
  documents: "src/**/*.tsx",
  generates: {
    "src/gql/": {
      preset: "client",
      plugins: []
    }
  }
};

export default config;

دعنا نفصل خيارات التكوين الرئيسية:

الخطوة 4: كتابة أول استعلام GraphQL لك

الآن بعد أن تم تكوين graphql-codegen، دعنا نكتب استعلام GraphQL لجلب منشورات المدونة الخاصة بنا. أنشئ ملفًا جديدًا src/components/Posts.tsx:TypeScript

import { gql } from '../gql/gql';
import { useQuery } from '@apollo/client';

const GET_POSTS = gql(`
  query GetPosts {
    allFilms {
      films {
        id
        title
        director
        releaseDate
      }
    }
  }
`);

const Posts = () => {
  const { loading, error, data } = useQuery(GET_POSTS);

  if (loading) return <p>Loading...</p>;
  if (error) return <p>Error :(</p>;

  return (
    <div>
      {data?.allFilms?.films?.map((film) => (
        <div key={film?.id}>
          <h2>{film?.title}</h2>
          <p>Director: {film?.director}</p>
          <p>Release Date: {film?.releaseDate}</p>
        </div>
      ))}
    </div>
  );
};

export default Posts;

لاحظ أننا نستورد دالة gql من الملف الذي تم إنشاؤه src/gql/gql.ts. هذه هي دالة gql التي يوفرها client-preset وهي التي تمكن سحر استنتاج الأنواع (type inference).

الخطوة 5: تشغيل graphql-codegen ورؤية السحر

الآن، قم بتشغيل سكريبت codegen من ملف package.json الخاص بك:Bash

npm run codegen

سيقوم هذا الأمر بفحص المخطط، والعثور على استعلام GET_POSTS الخاص بك، وتوليد أنواع TypeScript المقابلة في دليل src/gql.

إذا قمت الآن بفحص الكائن data الذي يعيده خطاف useQuery في Posts.tsx، فسترى أنه مكتوب بالكامل (fully typed)! ستوفر بيئة التطوير المتكاملة (IDE) الخاصة بك إكمالًا تلقائيًا لـ data.allFilms.films، وسيُحذرك TypeScript إذا حاولت الوصول إلى حقل غير موجود في الاستعلام.

تعمق أكبر: مثال عملي لواجهة أمامية لمدونة

دعنا نوسع مثالنا لترسيخ فهمك. تخيل أن مدونتنا لديها مخطط أكثر تقليدية:GraphQL

type Author {
  id: ID!
  name: String!
}

type Post {
  id: ID!
  title: String!
  content: String!
  author: Author!
}

type Query {
  posts: [Post!]!
  post(id: ID!): Post
}

type Mutation {
  createPost(title: String!, content: String!, authorId: ID!): Post!
}

لنفترض أن هذا المخطط يعمل على http://localhost:4000/graphql. سنقوم بتحديث ملف codegen.ts الخاص بنا وفقًا لذلك:TypeScript

// codegen.ts
// ...
schema: "http://localhost:4000/graphql",
// ...

الآن، دعنا ننشئ مكونًا لعرض منشور واحد وآخر لإنشاء منشور جديد.

جلب منشور واحدTypeScript

// src/components/Post.tsx
import { gql } from '../gql/gql';
import { useQuery } from '@apollo/client';
import { useParams } from 'react-router-dom';

const GET_POST = gql(`
  query GetPost($id: ID!) {
    post(id: $id) {
      id
      title
      content
      author {
        id
        name
      }
    }
  }
`);

const Post = () => {
  const { id } = useParams<{ id: string }>();
  const { loading, error, data } = useQuery(GET_POST, {
    variables: { id },
  });

  if (loading) return <p>Loading...</p>;
  if (error) return <p>Error :(</p>;

  return (
    <div>
      <h2>{data?.post?.title}</h2>
      <p>By {data?.post?.author?.name}</p>
      <p>{data?.post?.content}</p>
    </div>
  );
};

export default Post;

بعد تشغيل npm run codegen، سيتم توليد أنواع GetPostQuery ومتغيراتها، مما يوفر سلامة الأنواع لخطاف useQuery ونتيجته.

إنشاء منشور جديدTypeScript

// src/components/CreatePost.tsx
import { gql } from '../gql/gql';
import { useMutation } from '@apollo/client';
import { useState } from 'react';

const CREATE_POST = gql(`
  mutation CreatePost($title: String!, $content: String!, $authorId: ID!) {
    createPost(title: $title, content: $content, authorId: $authorId) {
      id
    }
  }
`);

const CreatePost = () => {
  const [title, setTitle] = useState('');
  const [content, setContent] = useState('');
  const [createPost, { data, loading, error }] = useMutation(CREATE_POST);

  const handleSubmit = (e: React.FormEvent) => {
    e.preventDefault();
    createPost({ variables: { title, content, authorId: '1' } }); // Assuming authorId '1' for simplicity
  };

  return (
    <form onSubmit={handleSubmit}>
      <input
        type="text"
        placeholder="Title"
        value={title}
        onChange={(e) => setTitle(e.target.value)}
      />
      <textarea
        placeholder="Content"
        value={content}
        onChange={(e) => setContent(e.target.value)}
      />
      <button type="submit" disabled={loading}>
        {loading ? 'Creating...' : 'Create Post'}
      </button>
      {error && <p>Error creating post: {error.message}</p>}
      {data && <p>Post created with ID: {data.createPost.id}</p>}
    </form>
  );
};

export default CreatePost;

هنا، يقوم graphql-codegen بتوليد أنواع CreatePostMutation ومتغيراتها. يضمن هذا أنه عند استدعاء دالة createPost، فإنك تمرر الأنواع الصحيحة لـ title، content، وauthorId.

مفاهيم متقدمة وأفضل الممارسات

مع ازدياد راحتك في استخدام graphql-codegen، ستصادف ميزات أكثر تقدمًا وأفضل الممارسات:

استكشاف الأخطاء الشائعة وإصلاحها

بينما يعتبر graphql-codegen أداة قوية، قد تواجه بعض المشكلات الشائعة كمبتدئ:

الخلاصة: احتضن المستقبل الآمن للأنواع

graphql-codegen هو أكثر من مجرد أداة لتوليد الكود؛ إنه تحول نموذجي في كيفية بناء التطبيقات باستخدام GraphQL. من خلال تبني الأتمتة والاستفادة من قوة مخططك، يمكنك إنشاء قواعد كود أكثر قوة وقابلية للصيانة وممتعة للعمل معها.

لقد قدم لك هذا البرنامج التعليمي أساسًا قويًا للبدء مع graphql-codegen. لقد غطينا المفاهيم الأساسية، وتطرقنا إلى مثال عملي، وتناولنا أفضل الممارسات. الرحلة لا تنتهي هنا. نظام graphql-codegen البيئي واسع، مع مجموعة غنية من الإضافات التي تلبي مختلف الأطر وحالات الاستخدام. أشجعك على استكشاف التوثيق الرسمي، وتجربة إضافات مختلفة، واكتشاف كيف يمكن لـ graphql-codegen أن يحدث ثورة في سير عمل تطوير GraphQL الخاص بك. برمجة سعيدة!

💡
هل تريد أداة رائعة لاختبار واجهات برمجة التطبيقات (API Testing) تولد توثيقًا جميلًا لواجهات برمجة التطبيقات؟

هل تريد منصة متكاملة وشاملة لفريق المطورين الخاص بك للعمل معًا بأقصى إنتاجية؟

Apidog يلبي جميع متطلباتك، ويحل محل Postman بسعر أقل بكثير!
button

ممارسة تصميم API في Apidog

اكتشف طريقة أسهل لبناء واستخدام واجهات برمجة التطبيقات