上一篇聊到 GraphQL,使用 GraphQL 作為 API 規範的話可以避免日漸臃腫、不斷傳輸重複資料的問題,但對於開發體驗上還有個關鍵性的工具:GraphQL Code Generator 。
我在專案上體驗過 TypeScript 搭配上 GraphQL Code Generator 的 GraphQL 後,那個開發體驗真的讓人感受到驚艷。
DocumentNode
要介紹這個工具前,要先提一下什麼是 DocumentNode
,目前常見的各種 GraphQL Client 工具,在做請求時會把 Query 的相關資訊透過 DocumentNode
的格式送進去,舉例來說使用 @apollo/client
時我們可能會這樣用:
import { gql } from '@apollo/client'
const postsQueryDocument = gql`
query Posts {
posts {
id
title
}
}
`
// `client` is a `new ApolloClient` Instance
const { data } = await client.query({ query: postsQueryDocument })
這時 postsQueryDocument
的 type 其實就是 DocumentNode
:
DocumentNode
當我們直接像上面的範例這樣使用時,GraphQL 為我們帶來了最大的靈活性,在每次的請求時決定需要的資料,但缺點也相當明顯。
第一個問題在 GraphQL 的請求散落各地,未來如果出現 API schema 的調整,可能會產生不小的麻煩。
另一個問題就是自由奔放的 any
了,如果直接這樣使用的話, data
會是 any
的型別,讓我們難以享受 TypeScript 的好處。
const { data } = await client.query({ query: postsQueryDocument })
但如果每次的請求都手動維護型別的話,不也是個麻煩的工作嗎?
interface PostQuery {
posts: {
id: string
title: string
}[]
}
const { data } = await client.query<PostQuery>({ query: postsQueryDocument })
其實這套工具最主要的作用就是自動化的建立出 GraphQL 的 TypedDocumentNode
,也就是含有型別資料的 DocumentNode
,會自動去從你設定的 GraphQL endpoint 取的最新的 schema,藉此來建立 TypedDocumentNode
將你的 Query 資料帶上型別。
使用方式並不困難,只要依照官方文件的安裝流程在專案中安裝好套件,然後我們將請求的 Query 資料統一集中在一個目錄中,不同的 Query 可以分別儲存成不同的 .gql
的檔案。
然後進行一些基礎設置(官方文件設定檔相關說明),定義好 schema
網址、documents
gql 檔案的位置、generates 輸出的檔案名稱等資訊就完成啦。
而未來我們在使用時,只要透過 npx graphql-codegen ./
的指令,就可以讓 GraphQL Code Generator 幫我們自動產出帶有型別的 TypedDocumentNode
來使用了,如果 API schema 有所調整時也會提醒我們的 .gql
發生錯誤必須更新,讓 API 的管理更加輕鬆。
如果覺得手動 npx graphql-codegen ./
太過麻煩,其實也可以考慮設定 package.json
的 script
,幫忙在每次啟動 dev server 時更新之類作法。
如果是使用 Vite 的朋友,可以使用 Vite Plugin GraphQL Codegen 這個工具幫忙,會自動在 dev server 啟動期間,自動的監聽並更新 TypedDocumentNode
與 schema 噢。