วิธีใช้ GraphQL Codegen ฉบับเริ่มต้น

Maurice Odida

Maurice Odida

20 June 2025

วิธีใช้ GraphQL Codegen ฉบับเริ่มต้น

ในโลกของการพัฒนาเว็บที่เปลี่ยนแปลงตลอดเวลา GraphQL ได้กลายเป็นทางเลือกที่ทรงพลังแทน REST API แบบดั้งเดิม โดยให้ความสามารถแก่ไคลเอนต์ในการร้องขอข้อมูลที่ต้องการได้อย่างแม่นยำ อย่างไรก็ตาม ความยืดหยุ่นนี้อาจนำมาซึ่งชุดความท้าทายใหม่ๆ โดยเฉพาะอย่างยิ่งเมื่อต้องรักษาความปลอดภัยของประเภท (type safety) ระหว่างส่วนหน้า (frontend) และส่วนหลัง (backend) นี่คือจุดที่ graphql-codegen เข้ามามีบทบาท ซึ่งเป็นเครื่องมือปฏิวัติที่ช่วยสร้างโค้ดที่มีประเภท (typed code) จากสคีมา GraphQL ของคุณโดยอัตโนมัติ ช่วยเพิ่มประสิทธิภาพเวิร์กโฟลว์การพัฒนาของคุณและกำจัดข้อผิดพลาดที่เกิดขึ้นในขณะรันไทม์จำนวนมาก

บทความนี้จะทำหน้าที่เป็นคู่มือของคุณในการทำความเข้าใจและเชี่ยวชาญ graphql-codegen เราจะเริ่มต้นด้วยแนวคิดพื้นฐาน พาคุณไปดูตัวอย่างการตั้งค่าและกำหนดค่าเครื่องมือแบบทีละขั้นตอน และสำรวจแนวปฏิบัติที่ดีที่สุดสำหรับการรวมเข้ากับโปรเจกต์ของคุณ เมื่อจบคู่มือนี้ คุณจะพร้อมที่จะใช้ประโยชน์จาก graphql-codegen เพื่อสร้างแอปพลิเคชันที่แข็งแกร่ง บำรุงรักษาง่าย และปลอดภัยด้านประเภทมากขึ้น

💡
ต้องการเครื่องมือทดสอบ API ที่ยอดเยี่ยมซึ่งสร้าง เอกสาร API ที่สวยงาม หรือไม่?

ต้องการแพลตฟอร์มแบบ All-in-One ที่รวมทุกอย่างสำหรับทีมพัฒนาของคุณเพื่อทำงานร่วมกันด้วย ประสิทธิภาพสูงสุด หรือไม่?

Apidog ตอบสนองทุกความต้องการของคุณ และ แทนที่ Postman ด้วยราคาที่ย่อมเยากว่ามาก!
button

graphql-codegen คืออะไร และทำไมคุณถึงต้องการมัน?

โดยพื้นฐานแล้ว graphql-codegen เป็นเครื่องมือบรรทัดคำสั่งที่ตรวจสอบสคีมา GraphQL และการดำเนินการ GraphQL ของคุณ (queries, mutations, และ subscriptions) และสร้างโค้ดในภาษาต่างๆ สำหรับคู่มือสำหรับผู้เริ่มต้นนี้ เราจะเน้นที่กรณีการใช้งานที่ได้รับความนิยมมากที่สุด: การสร้างประเภท TypeScript และ hooks สำหรับแอปพลิเคชันส่วนหน้า

ปัญหาหลักที่ graphql-codegen แก้ไขคือกระบวนการที่น่าเบื่อและมีแนวโน้มที่จะเกิดข้อผิดพลาดในการเขียน TypeScript interfaces ด้วยตนเองสำหรับโครงสร้างข้อมูลของ GraphQL API และผลลัพธ์ของการ queries ของคุณ หากไม่มีเครื่องมือนี้ นักพัฒนาจะต้องทำงานกับข้อมูลที่ไม่มีประเภท (type) (ทำให้สูญเสียประโยชน์ของ TypeScript) หรือใช้เวลาจำนวนมากในการสร้างและบำรุงรักษาประเภทที่อาจล้าสมัยได้ง่ายเมื่อ API มีการเปลี่ยนแปลง

ประโยชน์ของการนำ graphql-codegen มาใช้มีมากมาย:

แนวทางนี้สอดคล้องอย่างสมบูรณ์แบบกับปรัชญาการพัฒนาแบบ "schema-first" ซึ่งสคีมา GraphQL ทำหน้าที่เป็นแหล่งความจริงเดียวสำหรับ API ของคุณ

เริ่มต้น: การตั้งค่า graphql-codegen ครั้งแรกของคุณ

มาเจาะลึกถึงการใช้งานจริงของ graphql-codegen สำหรับบทช่วยสอนนี้ เราจะถือว่าคุณมีความเข้าใจพื้นฐานเกี่ยวกับ GraphQL, TypeScript และได้ติดตั้ง Node.js รวมถึงตัวจัดการแพ็กเกจ (เช่น npm หรือ yarn) ไว้แล้ว

เป้าหมายของเราคือการตั้งค่า graphql-codegen สำหรับแอปพลิเคชัน React อย่างง่ายที่แสดงรายการโพสต์บล็อก

ขั้นตอนที่ 1: การเริ่มต้นโปรเจกต์และ Dependencies

ขั้นแรก มาสร้างโปรเจกต์ React ใหม่ด้วย TypeScript และติดตั้ง dependencies ที่จำเป็น 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

นี่คือรายละเอียดของ dependencies ที่เราติดตั้ง:

ขั้นตอนที่ 2: ตัวช่วยการเริ่มต้น graphql-codegen

วิธีที่ง่ายที่สุดในการเริ่มต้นใช้งาน graphql-codegen คือการใช้ตัวช่วยการเริ่มต้น (initialization wizard) รันคำสั่งต่อไปนี้ในไดเรกทอรีหลักของโปรเจกต์ของคุณ 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 Query แรกของคุณ

เมื่อตั้งค่า graphql-codegen เสร็จแล้ว มาเขียน GraphQL query เพื่อดึงโพสต์บล็อกของเรากัน สร้างไฟล์ใหม่ 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>กำลังโหลด...</p>;
  if (error) return <p>เกิดข้อผิดพลาด :(</p>;

  return (
    <div>
      {data?.allFilms?.films?.map((film) => (
        <div key={film?.id}>
          <h2>{film?.title}</h2>
          <p>ผู้กำกับ: {film?.director}</p>
          <p>วันที่เผยแพร่: {film?.releaseDate}</p>
        </div>
      ))}
    </div>
  );
};

export default Posts;

สังเกตว่าเรากำลัง import ฟังก์ชัน gql จากไฟล์ที่สร้างขึ้น src/gql/gql.ts นี่คือฟังก์ชัน gql ที่จัดทำโดย client-preset และเป็นสิ่งที่ช่วยให้เกิดความมหัศจรรย์ของการอนุมานประเภท (type inference)

ขั้นตอนที่ 5: การรัน graphql-codegen และชมความมหัศจรรย์

ตอนนี้ รันสคริปต์ codegen จาก package.json ของคุณ: Bash

npm run codegen

คำสั่งนี้จะตรวจสอบสคีมา ค้นหา query GET_POSTS ของคุณ และสร้างประเภท TypeScript ที่เกี่ยวข้องในไดเรกทอรี src/gql

หากตอนนี้คุณตรวจสอบ object data ที่ส่งคืนโดย hook useQuery ใน Posts.tsx คุณจะเห็นว่ามันมีประเภท (type) ครบถ้วน! IDE ของคุณจะให้ autocompletion สำหรับ data.allFilms.films และ TypeScript จะเตือนคุณหากคุณพยายามเข้าถึง field ที่ไม่มีอยู่ใน query

เจาะลึกยิ่งขึ้น: ตัวอย่างแอปพลิเคชันส่วนหน้าบล็อกเชิงปฏิบัติ

มาขยายตัวอย่างของเราเพื่อเสริมสร้างความเข้าใจของคุณ ลองจินตนาการว่าบล็อกของเรามีสคีมาที่ดั้งเดิมกว่า: 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",
// ...

ตอนนี้ มาสร้าง component เพื่อแสดงโพสต์เดียว และอีกอันเพื่อสร้างโพสต์ใหม่

การดึงโพสต์เดียว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>กำลังโหลด...</p>;
  if (error) return <p>เกิดข้อผิดพลาด :(</p>;

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

export default Post;

หลังจากรัน npm run codegen ประเภทสำหรับ GetPostQuery และตัวแปรของมันจะถูกสร้างขึ้น ซึ่งให้ความปลอดภัยด้านประเภทสำหรับ hook 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="ชื่อเรื่อง"
        value={title}
        onChange={(e) => setTitle(e.target.value)}
      />
      <textarea
        placeholder="เนื้อหา"
        value={content}
        onChange={(e) => setContent(e.target.value)}
      />
      <button type="submit" disabled={loading}>
        {loading ? 'กำลังสร้าง...' : 'สร้างโพสต์'}
      </button>
      {error && <p>เกิดข้อผิดพลาดในการสร้างโพสต์: {error.message}</p>}
      {data && <p>สร้างโพสต์แล้วด้วย ID: {data.createPost.id}</p>}
    </form>
  );
};

export default CreatePost;

ที่นี่ graphql-codegen สร้างประเภทสำหรับ CreatePostMutation และตัวแปรของมัน ซึ่งช่วยให้มั่นใจว่าเมื่อคุณเรียกใช้ฟังก์ชัน createPost คุณจะส่งประเภทที่ถูกต้องสำหรับ title, content, และ authorId

แนวคิดขั้นสูงและแนวปฏิบัติที่ดีที่สุด

เมื่อคุณคุ้นเคยกับ graphql-codegen มากขึ้น คุณจะพบคุณสมบัติขั้นสูงและแนวปฏิบัติที่ดีที่สุดเพิ่มเติม:

การแก้ไขปัญหาทั่วไป

แม้ว่า graphql-codegen จะเป็นเครื่องมือที่ทรงพลัง คุณอาจพบปัญหาทั่วไปบางอย่างในฐานะผู้เริ่มต้น:

บทสรุป: โอบรับอนาคตที่ปลอดภัยด้านประเภท

graphql-codegen เป็นมากกว่าแค่เครื่องมือสร้างโค้ด เป็นการเปลี่ยนกระบวนทัศน์ (paradigm shift) ในวิธีการสร้างแอปพลิเคชันด้วย GraphQL ด้วยการนำระบบอัตโนมัติมาใช้และใช้ประโยชน์จากพลังของสคีมาของคุณ คุณสามารถสร้าง codebases ที่แข็งแกร่ง บำรุงรักษาง่าย และน่าทำงานด้วยมากขึ้น

บทช่วยสอนนี้ได้มอบพื้นฐานที่มั่นคงสำหรับการเริ่มต้นใช้งาน graphql-codegen เราได้ครอบคลุมแนวคิดหลักๆ พาคุณไปดูตัวอย่างเชิงปฏิบัติ และกล่าวถึงแนวปฏิบัติที่ดีที่สุด การเดินทางไม่ได้สิ้นสุดเพียงแค่นี้ ระบบนิเวศของ graphql-codegen นั้นกว้างใหญ่ มี plugins จำนวนมากที่รองรับเฟรมเวิร์กและกรณีการใช้งานต่างๆ ผมขอแนะนำให้คุณสำรวจเอกสารทางการ ทดลองใช้ plugins ต่างๆ และค้นพบว่า graphql-codegen สามารถปฏิวัติเวิร์กโฟลว์การพัฒนา GraphQL ของคุณได้อย่างไร มีความสุขกับการเขียนโค้ด!

💡
ต้องการเครื่องมือทดสอบ API ที่ยอดเยี่ยมซึ่งสร้าง เอกสาร API ที่สวยงาม หรือไม่?

ต้องการแพลตฟอร์มแบบ All-in-One ที่รวมทุกอย่างสำหรับทีมพัฒนาของคุณเพื่อทำงานร่วมกันด้วย ประสิทธิภาพสูงสุด หรือไม่?

Apidog ตอบสนองทุกความต้องการของคุณ และ แทนที่ Postman ด้วยราคาที่ย่อมเยากว่ามาก!
button

ฝึกการออกแบบ API แบบ Design-first ใน Apidog

ค้นพบวิธีที่ง่ายขึ้นในการสร้างและใช้ API