Hướng Dẫn Sử Dụng graphql-codegen Cho Người Mới Bắt Đầu

Maurice Odida

Maurice Odida

20 tháng 6 2025

Hướng Dẫn Sử Dụng graphql-codegen Cho Người Mới Bắt Đầu

Trong bối cảnh phát triển web không ngừng thay đổi, GraphQL đã nổi lên như một giải pháp thay thế mạnh mẽ cho các REST API truyền thống, mang đến cho các client khả năng yêu cầu chính xác dữ liệu mà họ cần. Tuy nhiên, sự linh hoạt này có thể tạo ra một loạt thách thức mới, đặc biệt là trong việc duy trì an toàn kiểu dữ liệu (type safety) giữa frontend và backend. Đây là lúc graphql-codegen xuất hiện, một công cụ mang tính cách mạng giúp tự động tạo mã có kiểu dữ liệu (typed code) từ schema GraphQL của bạn, tăng tốc quy trình phát triển và loại bỏ toàn bộ các lỗi xảy ra trong thời gian chạy (runtime errors).

Bài viết này sẽ đóng vai trò là hướng dẫn giúp bạn hiểu và làm chủ graphql-codegen. Chúng ta sẽ bắt đầu với các khái niệm cơ bản, đi qua một ví dụ thực tế từng bước về cách thiết lập và cấu hình công cụ, và khám phá các phương pháp hay nhất để tích hợp nó vào dự án của bạn. Cuối hướng dẫn này, bạn sẽ được trang bị kiến thức để tận dụng graphql-codegen xây dựng các ứng dụng mạnh mẽ hơn, dễ bảo trì hơn và an toàn kiểu dữ liệu hơn.

💡
Bạn muốn một công cụ kiểm thử API tuyệt vời có thể tạo ra Tài liệu API đẹp mắt?

Bạn muốn một nền tảng tích hợp, Tất cả trong Một cho Nhóm Phát triển của bạn làm việc cùng nhau với năng suất tối đa?

Apidog đáp ứng mọi yêu cầu của bạn và thay thế Postman với mức giá phải chăng hơn nhiều!
button

graphql-codegen là gì và Tại sao bạn cần nó?

Về cốt lõi, graphql-codegen là một công cụ dòng lệnh (command-line tool) kiểm tra schema GraphQL và các thao tác GraphQL (queries, mutations, và subscriptions) của bạn, sau đó tạo ra mã bằng nhiều ngôn ngữ khác nhau. Với mục đích của hướng dẫn dành cho người mới bắt đầu này, chúng ta sẽ tập trung vào trường hợp sử dụng phổ biến nhất của nó: tạo các kiểu TypeScript và hooks cho các ứng dụng frontend.

Vấn đề chính mà graphql-codegen giải quyết là quy trình tẻ nhạt và dễ gây lỗi khi phải tự viết các interface TypeScript cho cấu trúc dữ liệu của API GraphQL và kết quả của các query. Nếu không có nó, các nhà phát triển sẽ phải làm việc với dữ liệu không có kiểu (mất đi lợi ích của TypeScript) hoặc dành nhiều thời gian tạo và duy trì các kiểu dữ liệu có thể dễ dàng trở nên lỗi thời khi API phát triển.

Lợi ích của việc áp dụng graphql-codegen rất đa dạng:

Cách tiếp cận này hoàn toàn phù hợp với triết lý phát triển "schema-first", nơi schema GraphQL đóng vai trò là nguồn thông tin duy nhất cho API của bạn.

Bắt đầu: Thiết lập graphql-codegen đầu tiên của bạn

Hãy cùng đi sâu vào các khía cạnh thực tế của việc sử dụng graphql-codegen. Đối với hướng dẫn này, chúng ta sẽ giả định bạn có hiểu biết cơ bản về GraphQL, TypeScript, và đã cài đặt Node.js cùng với một trình quản lý gói (như npm hoặc yarn).

Mục tiêu của chúng ta là thiết lập graphql-codegen cho một ứng dụng React đơn giản hiển thị danh sách các bài đăng blog.

Bước 1: Khởi tạo dự án và các dependency

Đầu tiên, hãy tạo một dự án React mới với TypeScript và cài đặt các dependency cần thiết.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

Đây là giải thích chi tiết về các dependency chúng ta đã cài đặt:

Bước 2: Trình hướng dẫn khởi tạo graphql-codegen

Cách dễ nhất để bắt đầu với graphql-codegen là sử dụng trình hướng dẫn khởi tạo của nó. Chạy lệnh sau trong thư mục gốc của dự án của bạn:Bash

npx graphql-codegen init

Trình hướng dẫn sẽ hỏi bạn một loạt câu hỏi để giúp cấu hình dự án của bạn. Dưới đây là một bộ câu trả lời điển hình cho kịch bản ứng dụng blog của chúng ta:

Sau khi trả lời các câu hỏi này, trình hướng dẫn sẽ tạo một tệp codegen.ts trong thư mục gốc của dự án và thêm một script codegen vào tệp package.json của bạn.

Bước 3: Hiểu về tệp cấu hình (codegen.ts)

Tệp codegen.ts là trái tim của thiết lập graphql-codegen của bạn. Hãy xem một phiên bản đơn giản hóa của những gì trình hướng dẫn tạo ra: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;

Hãy phân tích các tùy chọn cấu hình chính:

Bước 4: Viết Query GraphQL đầu tiên của bạn

Bây giờ graphql-codegen đã được cấu hình, hãy viết một query GraphQL để lấy các bài đăng blog của chúng ta. Tạo một tệp mới 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>Đang tải...</p>;
  if (error) return <p>Lỗi :( </p>;

  return (
    <div>
      {data?.allFilms?.films?.map((film) => (
        <div key={film?.id}>
          <h2>{film?.title}</h2>
          <p>Đạo diễn: {film?.director}</p>
          <p>Ngày phát hành: {film?.releaseDate}</p>
        </div>
      ))}
    </div>
  );
};

export default Posts;

Lưu ý rằng chúng ta đang import một hàm gql từ tệp src/gql/gql.ts đã được tạo ra. Đây là hàm gql được cung cấp bởi client-preset và chính nó là thứ cho phép phép màu suy luận kiểu dữ liệu (type inference) xảy ra.

Bước 5: Chạy graphql-codegen và thấy phép màu

Bây giờ, chạy script codegen từ tệp package.json của bạn:Bash

npm run codegen

Lệnh này sẽ kiểm tra schema, tìm query GET_POSTS của bạn và tạo ra các kiểu TypeScript tương ứng trong thư mục src/gql.

Nếu bây giờ bạn kiểm tra đối tượng data được trả về bởi hook useQuery trong Posts.tsx, bạn sẽ thấy nó được gõ đầy đủ! IDE của bạn sẽ cung cấp tính năng tự động hoàn thành cho data.allFilms.films, và TypeScript sẽ cảnh báo bạn nếu bạn cố gắng truy cập một trường không tồn tại trong query.

Đi sâu hơn: Một ví dụ frontend blog thực tế

Hãy mở rộng ví dụ của chúng ta để củng cố sự hiểu biết của bạn. Hãy tưởng tượng blog của chúng ta có một schema truyền thống hơn: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!
}

Giả sử schema này đang chạy trên http://localhost:4000/graphql. Chúng ta sẽ cập nhật tệp codegen.ts tương ứng:TypeScript

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

Bây giờ, hãy tạo một component để hiển thị một bài đăng duy nhất và một component khác để tạo bài đăng mới.

Lấy một bài đăng duy nhấtTypeScript

// 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>Đang tải...</p>;
  if (error) return <p>Lỗi :( </p>;

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

export default Post;

Sau khi chạy npm run codegen, các kiểu cho GetPostQuery và các biến của nó sẽ được tạo ra, cung cấp an toàn kiểu dữ liệu cho hook useQuery và kết quả của nó.

Tạo một bài đăng mớiTypeScript

// 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' } }); // Giả sử authorId '1' để đơn giản
  };

  return (
    <form onSubmit={handleSubmit}>
      <input
        type="text"
        placeholder="Tiêu đề"
        value={title}
        onChange={(e) => setTitle(e.target.value)}
      />
      <textarea
        placeholder="Nội dung"
        value={content}
        onChange={(e) => setContent(e.target.value)}
      />
      <button type="submit" disabled={loading}>
        {loading ? 'Đang tạo...' : 'Tạo bài đăng'}
      </button>
      {error && <p>Lỗi khi tạo bài đăng: {error.message}</p>}
      {data && <p>Bài đăng đã được tạo với ID: {data.createPost.id}</p>}
    </form>
  );
};

export default CreatePost;

Ở đây, graphql-codegen tạo ra các kiểu cho CreatePostMutation và các biến của nó. Điều này đảm bảo rằng khi bạn gọi hàm createPost, bạn đang truyền đúng kiểu dữ liệu cho title, content, và authorId.

Các khái niệm nâng cao và phương pháp hay nhất

Khi bạn đã quen thuộc hơn với graphql-codegen, bạn sẽ gặp các tính năng nâng cao và phương pháp hay nhất:

Khắc phục sự cố thường gặp

Mặc dù graphql-codegen là một công cụ mạnh mẽ, bạn có thể gặp phải một vài vấn đề phổ biến khi mới bắt đầu:

Kết luận: Chào đón tương lai an toàn kiểu dữ liệu

graphql-codegen không chỉ là một công cụ tạo mã; nó là một sự thay đổi mô hình trong cách chúng ta xây dựng ứng dụng với GraphQL. Bằng cách tận dụng tự động hóa và sức mạnh của schema, bạn có thể tạo ra các codebase mạnh mẽ hơn, dễ bảo trì hơn và thú vị hơn khi làm việc.

Hướng dẫn này đã cung cấp cho bạn nền tảng vững chắc để bắt đầu với graphql-codegen. Chúng ta đã đi qua các khái niệm cốt lõi, thực hiện một ví dụ thực tế và chạm đến các phương pháp hay nhất. Hành trình không kết thúc ở đây. Hệ sinh thái graphql-codegen rất rộng lớn, với một bộ sưu tập phong phú các plugin phục vụ cho nhiều framework và trường hợp sử dụng khác nhau. Tôi khuyến khích bạn khám phá tài liệu chính thức, thử nghiệm với các plugin khác nhau và khám phá cách graphql-codegen có thể cách mạng hóa quy trình phát triển GraphQL của bạn. Chúc bạn code vui vẻ!

💡
Bạn muốn một công cụ kiểm thử API tuyệt vời có thể tạo ra Tài liệu API đẹp mắt?

Bạn muốn một nền tảng tích hợp, Tất cả trong Một cho Nhóm Phát triển của bạn làm việc cùng nhau với năng suất tối đa?

Apidog đáp ứng mọi yêu cầu của bạn và thay thế Postman với mức giá phải chăng hơn nhiều!
button

Thực hành thiết kế API trong Apidog

Khám phá cách dễ dàng hơn để xây dựng và sử dụng API