ในโลกของการพัฒนาเว็บที่เปลี่ยนแปลงตลอดเวลา GraphQL ได้กลายเป็นทางเลือกที่ทรงพลังแทน REST API แบบดั้งเดิม โดยให้ความสามารถแก่ไคลเอนต์ในการร้องขอข้อมูลที่ต้องการได้อย่างแม่นยำ อย่างไรก็ตาม ความยืดหยุ่นนี้อาจนำมาซึ่งชุดความท้าทายใหม่ๆ โดยเฉพาะอย่างยิ่งเมื่อต้องรักษาความปลอดภัยของประเภท (type safety) ระหว่างส่วนหน้า (frontend) และส่วนหลัง (backend) นี่คือจุดที่ graphql-codegen
เข้ามามีบทบาท ซึ่งเป็นเครื่องมือปฏิวัติที่ช่วยสร้างโค้ดที่มีประเภท (typed code) จากสคีมา GraphQL ของคุณโดยอัตโนมัติ ช่วยเพิ่มประสิทธิภาพเวิร์กโฟลว์การพัฒนาของคุณและกำจัดข้อผิดพลาดที่เกิดขึ้นในขณะรันไทม์จำนวนมาก
บทความนี้จะทำหน้าที่เป็นคู่มือของคุณในการทำความเข้าใจและเชี่ยวชาญ graphql-codegen
เราจะเริ่มต้นด้วยแนวคิดพื้นฐาน พาคุณไปดูตัวอย่างการตั้งค่าและกำหนดค่าเครื่องมือแบบทีละขั้นตอน และสำรวจแนวปฏิบัติที่ดีที่สุดสำหรับการรวมเข้ากับโปรเจกต์ของคุณ เมื่อจบคู่มือนี้ คุณจะพร้อมที่จะใช้ประโยชน์จาก graphql-codegen
เพื่อสร้างแอปพลิเคชันที่แข็งแกร่ง บำรุงรักษาง่าย และปลอดภัยด้านประเภทมากขึ้น
ต้องการแพลตฟอร์มแบบ All-in-One ที่รวมทุกอย่างสำหรับทีมพัฒนาของคุณเพื่อทำงานร่วมกันด้วย ประสิทธิภาพสูงสุด หรือไม่?
Apidog ตอบสนองทุกความต้องการของคุณ และ แทนที่ Postman ด้วยราคาที่ย่อมเยากว่ามาก!
graphql-codegen
คืออะไร และทำไมคุณถึงต้องการมัน?
โดยพื้นฐานแล้ว graphql-codegen
เป็นเครื่องมือบรรทัดคำสั่งที่ตรวจสอบสคีมา GraphQL และการดำเนินการ GraphQL ของคุณ (queries, mutations, และ subscriptions) และสร้างโค้ดในภาษาต่างๆ สำหรับคู่มือสำหรับผู้เริ่มต้นนี้ เราจะเน้นที่กรณีการใช้งานที่ได้รับความนิยมมากที่สุด: การสร้างประเภท TypeScript และ hooks สำหรับแอปพลิเคชันส่วนหน้า
ปัญหาหลักที่ graphql-codegen
แก้ไขคือกระบวนการที่น่าเบื่อและมีแนวโน้มที่จะเกิดข้อผิดพลาดในการเขียน TypeScript interfaces ด้วยตนเองสำหรับโครงสร้างข้อมูลของ GraphQL API และผลลัพธ์ของการ queries ของคุณ หากไม่มีเครื่องมือนี้ นักพัฒนาจะต้องทำงานกับข้อมูลที่ไม่มีประเภท (type) (ทำให้สูญเสียประโยชน์ของ TypeScript) หรือใช้เวลาจำนวนมากในการสร้างและบำรุงรักษาประเภทที่อาจล้าสมัยได้ง่ายเมื่อ API มีการเปลี่ยนแปลง
ประโยชน์ของการนำ graphql-codegen
มาใช้มีมากมาย:
- ความปลอดภัยด้านประเภทแบบ End-to-End: ด้วยการสร้างประเภทโดยตรงจากสคีมาของคุณ
graphql-codegen
ช่วยให้มั่นใจว่าโค้ดส่วนหน้าของคุณจะซิงค์กับโมเดลข้อมูลของส่วนหลังเสมอ ซึ่งหมายความว่าคุณจะตรวจจับข้อผิดพลาดที่เกี่ยวข้องกับประเภทได้ตั้งแต่ตอนคอมไพล์ ก่อนที่ข้อผิดพลาดเหล่านั้นจะไปถึงผู้ใช้ของคุณนาน - ประสบการณ์นักพัฒนาที่ดีขึ้น: ด้วยประเภทที่ถูกสร้างขึ้น คุณจะได้รับคุณสมบัติเช่น autocompletion และคำแนะนำอัจฉริยะในโปรแกรมแก้ไขโค้ด ทำให้การพัฒนาเร็วขึ้นและมีประสิทธิภาพมากขึ้น ไม่ต้องเดารูปแบบการตอบสนองของ API อีกต่อไป!
- ลดโค้ดซ้ำซ้อน (Boilerplate):
graphql-codegen
ไม่เพียงแต่สร้างประเภทเท่านั้น แต่ยังสามารถสร้าง hooks ที่พร้อมใช้งานสำหรับ GraphQL clients ยอดนิยม เช่น Apollo Client และ React Query ซึ่งช่วยลดความจำเป็นในการเขียนโค้ดดึงข้อมูลที่ซ้ำซ้อน - บำรุงรักษาง่ายขึ้น: เมื่อสคีมา API ของคุณเปลี่ยนแปลง คำสั่งง่ายๆ ก็เพียงพอที่จะสร้างประเภทของคุณขึ้นใหม่ ทำให้ codebase ของคุณบำรุงรักษาและปรับปรุงโครงสร้างได้ง่ายขึ้นเมื่อเวลาผ่านไป
แนวทางนี้สอดคล้องอย่างสมบูรณ์แบบกับปรัชญาการพัฒนาแบบ "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 ที่เราติดตั้ง:
@apollo/client
: GraphQL client ยอดนิยมสำหรับ Reactgraphql
: peer dependency ที่จำเป็นสำหรับทั้ง Apollo Client และgraphql-codegen
@graphql-codegen/cli
: command-line interface สำหรับgraphql-codegen
@graphql-codegen/client-preset
: preset ที่ทันสมัยและคล่องตัวซึ่งช่วยให้การกำหนดค่าสำหรับแอปพลิเคชันฝั่งไคลเอนต์ง่ายขึ้นtypescript
: ตัวคอมไพเลอร์ TypeScript
ขั้นตอนที่ 2: ตัวช่วยการเริ่มต้น graphql-codegen
วิธีที่ง่ายที่สุดในการเริ่มต้นใช้งาน graphql-codegen
คือการใช้ตัวช่วยการเริ่มต้น (initialization wizard) รันคำสั่งต่อไปนี้ในไดเรกทอรีหลักของโปรเจกต์ของคุณ Bash
npx graphql-codegen init
ตัวช่วยจะถามคำถามหลายข้อเพื่อช่วยกำหนดค่าโปรเจกต์ของคุณ นี่คือชุดคำตอบทั่วไปสำหรับสถานการณ์แอปพลิเคชันบล็อกของเรา:
- คุณกำลังสร้างแอปพลิเคชันประเภทใด?
Application built with React
- สคีมาของคุณอยู่ที่ไหน? ระบุ URL ของ GraphQL API endpoint ของคุณ สำหรับบทช่วยสอนนี้ เราสามารถใช้ API ตัวอย่างที่เปิดเผยต่อสาธารณะ:
https://swapi-graphql.netlify.app/.netlify/functions/index
- การดำเนินการ (operations) และ fragments ของคุณอยู่ที่ไหน?
src/**/*.tsx
(นี่บอกgraphql-codegen
ให้มองหา GraphQL queries ในไฟล์.tsx
ทั้งหมดภายในไดเรกทอรีsrc
) - เลือก plugins: ตัวช่วยจะแนะนำชุด plugins ค่าเริ่มต้น ซึ่งรวมถึง
typescript
,typescript-operations
, และtypescript-react-apollo
เป็นจุดเริ่มต้นที่ดีเยี่ยม - จะเขียนไฟล์ที่สร้างขึ้นไว้ที่ไหน?
src/gql/
(นี่จะสร้างไดเรกทอรีใหม่src/gql
เพื่อเก็บไฟล์ที่สร้างขึ้น) - คุณต้องการสร้างไฟล์ introspection หรือไม่?
Yes
(นี่มีประโยชน์สำหรับการพัฒนาในเครื่องและส่วนขยาย IDE) - จะตั้งชื่อไฟล์กำหนดค่าว่าอะไร?
codegen.ts
- สคริปต์ใดใน package.json ที่ควรใช้รัน codegen?
codegen
หลังจากตอบคำถามเหล่านี้ ตัวช่วยจะสร้างไฟล์ 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;
มาทำความเข้าใจตัวเลือกการกำหนดค่าหลักๆ กัน:
overwrite: true
: นี่ทำให้มั่นใจว่าไฟล์ที่สร้างขึ้นที่มีอยู่จะถูกเขียนทับทุกครั้งที่คุณรันคำสั่งschema
: นี่ชี้ไปยังแหล่งที่มาของสคีมา GraphQL ของคุณ อาจเป็น URL ไปยัง endpoint ที่ทำงานอยู่ หรือไฟล์.graphql
หรือ.json
ในเครื่องdocuments
: นี่คือ glob pattern ที่บอกgraphql-codegen
ว่าจะค้นหา GraphQL operations (queries, mutations, และ fragments) ของคุณได้ที่ไหนgenerates
: นี่คือส่วนที่สำคัญที่สุดของการกำหนดค่า เป็น object ที่แต่ละ key แทนไฟล์หรือไดเรกทอรีผลลัพธ์ และ value กำหนดว่าจะสร้างอะไรpreset: "client"
:client-preset
เป็นวิธีที่ทรงพลังและแนะนำในการกำหนดค่าgraphql-codegen
สำหรับแอปพลิเคชันส่วนหน้า มันรวมหลาย plugins และมอบประสบการณ์ที่คล่องตัว มันสร้างฟังก์ชันgraphql
ที่คุณจะใช้ในการเขียน queries ของคุณ
ขั้นตอนที่ 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
มากขึ้น คุณจะพบคุณสมบัติขั้นสูงและแนวปฏิบัติที่ดีที่สุดเพิ่มเติม:
- Fragments:
graphql-codegen
รองรับ GraphQL fragments ได้อย่างยอดเยี่ยม คุณสามารถกำหนด fragments ในไฟล์.tsx
ของคุณ และgraphql-codegen
จะจัดการประเภทได้อย่างถูกต้อง ส่งเสริมการนำ dependencies ข้อมูลกลับมาใช้ใหม่และอยู่ร่วมกันสำหรับ components ของคุณ - การใช้ไฟล์
.graphql
: เพื่อการแยกส่วนที่ชัดเจนยิ่งขึ้น คุณสามารถเขียน GraphQL queries, mutations, และ fragments ของคุณในไฟล์.graphql
เฉพาะได้ เพียงแค่อัปเดต arraydocuments
ในไฟล์codegen.ts
ของคุณเพื่อรวมนามสกุลไฟล์นี้:documents: ["src/**/*.tsx", "src/**/*.graphql"]
- Custom Scalars: หากสคีมา GraphQL ของคุณใช้ custom scalars (เช่น
Date
,JSON
) คุณสามารถแมปพวกมันไปยังประเภท TypeScript ที่เกี่ยวข้องในไฟล์codegen.ts
ของคุณเพื่อรักษาความปลอดภัยด้านประเภท - Watch Mode: เพื่อประสบการณ์การพัฒนาที่ราบรื่น คุณสามารถรัน
graphql-codegen
ใน watch mode ได้ ซึ่งจะสร้างประเภทของคุณขึ้นใหม่โดยอัตโนมัติทุกครั้งที่คุณบันทึกไฟล์ที่มี GraphQL operation เพียงแค่เพิ่ม flag--watch
ลงในสคริปต์codegen
ในไฟล์package.json
ของคุณ:"codegen": "graphql-codegen --watch"
การแก้ไขปัญหาทั่วไป
แม้ว่า graphql-codegen
จะเป็นเครื่องมือที่ทรงพลัง คุณอาจพบปัญหาทั่วไปบางอย่างในฐานะผู้เริ่มต้น:
- "ไม่พบสคีมา" (Unable to find schema): ข้อผิดพลาดนี้มักหมายความว่าพาธ
schema
ในไฟล์codegen.ts
ของคุณไม่ถูกต้อง หรือเซิร์ฟเวอร์ GraphQL ไม่ได้ทำงานที่ที่อยู่ที่ระบุ - ข้อผิดพลาดในการกำหนดค่า Plugin: ตรวจสอบให้แน่ใจว่าคุณได้ติดตั้ง plugins ที่จำเป็นทั้งหมดแล้ว และการกำหนดค่าในไฟล์
codegen.ts
ถูกต้อง - ปัญหา Peer Dependency ของ
graphql
: ตรวจสอบให้แน่ใจว่าคุณได้ติดตั้งgraphql
เป็น direct dependency ในโปรเจกต์ของคุณ
บทสรุป: โอบรับอนาคตที่ปลอดภัยด้านประเภท
graphql-codegen
เป็นมากกว่าแค่เครื่องมือสร้างโค้ด เป็นการเปลี่ยนกระบวนทัศน์ (paradigm shift) ในวิธีการสร้างแอปพลิเคชันด้วย GraphQL ด้วยการนำระบบอัตโนมัติมาใช้และใช้ประโยชน์จากพลังของสคีมาของคุณ คุณสามารถสร้าง codebases ที่แข็งแกร่ง บำรุงรักษาง่าย และน่าทำงานด้วยมากขึ้น
บทช่วยสอนนี้ได้มอบพื้นฐานที่มั่นคงสำหรับการเริ่มต้นใช้งาน graphql-codegen
เราได้ครอบคลุมแนวคิดหลักๆ พาคุณไปดูตัวอย่างเชิงปฏิบัติ และกล่าวถึงแนวปฏิบัติที่ดีที่สุด การเดินทางไม่ได้สิ้นสุดเพียงแค่นี้ ระบบนิเวศของ graphql-codegen
นั้นกว้างใหญ่ มี plugins จำนวนมากที่รองรับเฟรมเวิร์กและกรณีการใช้งานต่างๆ ผมขอแนะนำให้คุณสำรวจเอกสารทางการ ทดลองใช้ plugins ต่างๆ และค้นพบว่า graphql-codegen
สามารถปฏิวัติเวิร์กโฟลว์การพัฒนา GraphQL ของคุณได้อย่างไร มีความสุขกับการเขียนโค้ด!
ต้องการแพลตฟอร์มแบบ All-in-One ที่รวมทุกอย่างสำหรับทีมพัฒนาของคุณเพื่อทำงานร่วมกันด้วย ประสิทธิภาพสูงสุด หรือไม่?
Apidog ตอบสนองทุกความต้องการของคุณ และ แทนที่ Postman ด้วยราคาที่ย่อมเยากว่ามาก!