GraphQL Code Generator 導入する
GraphQL Client (Apollo Client) 用の型定義を自動生成したいので、GraphQL Code Generator を導入する。
公式 Docs の以下を参考に進めていく。
"自動生成" って何が生成されるの...?
今までこう↓書かなきゃいけなかったものが、
import { gql, useQuery } from '@apollo/client';
interface PostQuery {
posts: {
id: string
title: string
author?: {
id: string
firstName: string
lastName: string
}
}[]
}
const postsQueryDocument = gql`
query Posts {
posts {
id
title
author {
id
firstName
lastName
}
}
}
`
const Posts = () => {
const { data } = useQuery<PostQuery>(postsQueryDocument);
// ...
}
これ↓で良くなる!
import { useQuery } from '@apollo/client';
import { postsQueryDocument } from './graphql/generated';
const Posts = () => {
const { data } = useQuery(postsQueryDocument);
// `result` is fully typed!
// ...
}
hooks の自動生成も可能
別途 plugin を利用し、しかるべき設定をすれば、Apollo Client の hooks を自動生成することもできるとのこと!こんな感じ↓
import { usePostsQuery } from './graphql/generated';
const Posts = () => {
const { data } = usePostsQuery();
// `result` is fully typed!
// ...
}
下準備
Install
まずは公式Docsの Installation に従って必要な package を Install する。
npm install graphql
npm install @graphql-codegen/cli
今回導入対象の既存 project にはすでに graphql
は入っているので、@graphql-codegen/cli
のみ instatll
version はこちら↓
"graphql": "^15.8.0",
"@graphql-codegen/cli": "^2.4.0",
Setup
Initialization Wizard#
Once installed, GraphQL Code Generator CLI can help you configure your project based on some popular flows:
Wizard に従ってセットアップを進めてみる。
npx graphql-codegen init
一部よくわからないものもあったが、とりあえず、こんな感じで答えてみた↓
Welcome to GraphQL Code Generator!
Answer few questions and we will setup everything for you.
? What type of application are you building? Application built with React
? Where is your schema?: (path or url) /api/graphql
? Where are your operations and fragments?: graphql/schema.graphql
? Pick plugins: TypeScript (required by other typescript plugins), TypeScript O
perations (operations and fragments), TypeScript React Apollo (typed components
and HOCs)
? Where to write the output: graphql/generated/graphql.tsx
? Do you want to generate an introspection file? Yes
? How to name the config file? codegen.yml
? What script in package.json should run the codegen? codegen
Fetching latest versions of selected plugins...
Config file generated at codegen.yml
$ npm install
To install the plugins.
$ npm run codegen
To run GraphQL Code Generator.
What type of application are you building
今回の project は Next.js ベースなので、"Application built with React" のみ選択。
Where are your operations and fragments
Nexus で schema.graphql
を自動生成しているので、その path を指定。
Pick plugins: (Press <space> to select, <a> to toggle all, <i> to invert sele
ction, and <enter> to proceed)
❯◉ TypeScript (required by other typescript plugins)
◉ TypeScript Operations (operations and fragments)
◉ TypeScript React Apollo (typed components and HOCs)
◯ TypeScript GraphQL files modules (declarations for .graphql files)
◯ TypeScript GraphQL document nodes (embedded GraphQL document)
◯ Introspection Fragment Matcher (for Apollo Client)
◯ Urql Introspection (for Urql Client)
とりあえず、デフォルトで選択されていた以下 3つを選択
- TypeScript (required by other typescript plugins)
- TypeScript Operations (operations and fragments)
- TypeScript React Apollo (typed components and HOCs)
Where to write the output
graphql 関連は graphql/ 下にまとめてるので、graphql/generated/graphql.tsx
に
Where is your schema?:
graphql の endpoint の path を指定 /api/graphql
Do you want to generate an introspection file?
何を introspect するのかわからないけど、とりあえず yes にしてみる
How to name the config file?
デフォの codegen.yml
に
What script in package.json should run the codegen?
とりあえず codegen で
これで完了。
以下 codegen.yml ファイルが生成され、package.json に codegen script が追加された。
overwrite: true
schema: "/api/graphql"
documents: "graphql/schema.graphql"
generates:
graphql/generated/graphql.tsx:
plugins:
- "typescript"
- "typescript-operations"
- "typescript-react-apollo"
./graphql.schema.json:
plugins:
- "introspection"
"scripts": {
"codegen": "graphql-codegen --config codegen.yml"
},
実行してみる
schema でエラー
実際にコマンド叩いてみたところエラーが出たので対応していく
npm run codegen
✔ Parse configuration
❯ Generate outputs
❯ Generate graphql/generated/graphql.tsx
✖ Load GraphQL schemas
→ Failed to load schema
Load GraphQL documents
Generate
❯ Generate ./graphql.schema.json
✖ Load GraphQL schemas
→ Failed to load schema
Load GraphQL documents
Generate
どうやら、schema file がロードできてないらしい
現状、こう↓なってるが path の指定だけだとダメみたい
schema: "/api/graphql"
公式 Docs を見ていく
localhost の url を指定すればよさそう
schema: http://localhost:3000/api/graphql
これで行けた
documents でエラー
次は Load GraphQL documents でエラー起きてるので対応していく。
✔ Parse configuration
❯ Generate outputs
❯ Generate graphql/generated/graphql.tsx
✔ Parse configuration
❯ Generate outputs
❯ Generate graphql/generated/graphql.tsx
✔ Load GraphQL schemas
✖ Load GraphQL documents
→ - graphql/schema.graphql
Generate
❯ Generate ./graphql.schema.json ✔ Load GraphQL schemas ✖ Load GraphQL documents
→ - graphql/schema.graphql
Generate
現状は、こう↓
documents: "graphql/schema.graphql"
そもそも、"GraphQL Documents" とは何なのか理解してないな...そっち優先だな
GraphQL Document とは...?
まずは GraphQL Code Generator の documents
に関する説明を見てみる
The documents field should point to your GraphQL documents: query, mutation, subscription and fragment
query, mutation, subscription and fragment ... もっと説明が欲しいな
他の説明をググる。
GraphQL document: A string written in the GraphQL language that defines one or more operations and fragments.
これだ。
"GraphQL Document" とは、GraphQL へ投げる query やら mutation やらの string のことを指すのか。
つまり、下の例の場合、
import { gql, useQuery } from '@apollo/client';
const GET_GREETING = gql`
query GetGreeting($language: String!) {
greeting(language: $language) {
message
}
}
`;
function Hello() {
const { loading, error, data } = useQuery(GET_GREETING, {
variables: { language: 'english' },
});
if (loading) return <p>Loading ...</p>;
return <h1>Hello {data.greeting.message}!</h1>;
}
gql
に渡しているこの↓部分が GraphQL Document と。
`
query GetGreeting($language: String!) {
greeting(language: $language) {
message
}
}
`
Apollo Client の API reference で useQuery
の型見にいく。
function useQuery<TData = any, TVariables = OperationVariables>(
query: DocumentNode,
options?: QueryHookOptions<TData, TVariables>,
): QueryResult<TData, TVariables> {}
DocumentNode
という型が "GraphQL Document" に対応してるのね
エラー対応に戻る
documents のエラー対応
今回の project の場合、GraphQL Documents は現状存在しないので消すことで対応。
最後のエラー
次は Generate でエラーでたので対応していく。
✔ Parse configuration
❯ Generate outputs
❯ Generate graphql/generated/graphql.tsx
✔ Load GraphQL schemas
✔ Load GraphQL documents
✖ Generate
→ Unable to find template plugin matching typescript-operations
❯ Generate ./graphql.schema.json
✔ Load GraphQL schemas
✔ Load GraphQL documents
✖ Generate
→ Unable to find template plugin matching introspection
plugins は package.json に追記されただけで、 install されてなかったので install する。
npm i
もう一度実行
✔ Parse configuration
❯ Generate outputs
✔ Parse configuration
✔ Generate outputs
完了!
修正後の codegen.yml
overwrite: true
schema: http://localhost:3000/api/graphql
generates:
graphql/generated/graphql.tsx:
plugins:
- 'typescript'
- 'typescript-operations'
- 'typescript-react-apollo'
./graphql.schema.json:
plugins:
- 'introspection'
この状態で npm run codegen
すると、graphql/generated/graphql.tsx
が生成される。
graphql/generated/graphql.tsx
には、schema.graphql
に対応する型定義が記載されている。
introspection は何をしているかは別途調べる
Apollo Client 用のセットアップ
ここから Apollo Client 用の自動生成ができるようにセットアップしていく。
1. Move all your GraphQL documents in dedicated .graphql files
GraphQL documents を ts, tsx から .graphql ファイルへ移動させることがファーストステップ。必須ではないがやっておくといいとのこと。
今回は既存のものは存在しないので、新規の .graphql を作成していく。
サンプルで Post を query するケースを想定して作ってみる。
posts.graphql
を作成。
query Posts {
posts {
id
title
content
}
}
2. Install the @graphql-codegen/typed-document-node plugin
以下の package を install する。
npm install @graphql-codegen/typed-document-node
npm install @graphql-codegen/typescript
npm install @graphql-codegen/typescript-operations
install された version はこちら↓
"@graphql-codegen/typed-document-node": "^2.2.3",
"@graphql-codegen/typescript": "^2.4.3",
"@graphql-codegen/typescript-operations": "^2.2.4",
3. Configure the plugin
- documents に Client-side で利用する
.graphql
のファイルの path を指定 - 先ほど install した 3つの plugin を指定
こんな感じ↓
schema: http://my-graphql-api.com/graphql
documents: './src/**/*.graphql'
generates:
./src/graphql-operations.ts:
plugins:
- typescript
- typescript-operations
- typed-document-node
4. Run the codegen and update your code
あとは codegen を実行すればOK
npm run generate
src/graphql-operations.ts
が自動生成され、PostsQuery
のデータ型と PostsDocument
という GraphQL Document が生成されているここを確認。
export type PostsQuery = { __typename?: 'Query', posts?: Array<{ __typename?: 'Post', id: string, title: string, content: string } | null> | null };
export const PostsDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"query","name":{"kind":"Name","value":"Posts"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"posts"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"title"}},{"kind":"Field","name":{"kind":"Name","value":"content"}}]}}]}}]} as unknown as DocumentNode<PostsQuery, PostsQueryVariables>;
実際に使ってみる
自動生成された型と GraphQL Document を useQuery()
に渡してあげる。
const Posts = () => {
const { data } = useQuery<PostsQuery>(PostsDocument);
// ...
}
型補完される!最高!
Apollo Client の hooks を自動生成
GraphQL Document の自動生成までできたので、次は hooks の自動生成ができるようにセットアップしていく。
@graphql-codegen/typescript-react-apollo
1. Install the 以下3つの plugin が必要になるので install する。
npm install @graphql-codegen/typescript-react-apollo
npm install @graphql-codegen/typescript
npm install @graphql-codegen/typescript-operations
GraphQL Document の自動生成のセットアップの段階で @graphql-codegen/typescript
と @graphql-codegen/typescript-operations
はすでに install しているので、別途 install するのは @graphql-codegen/typescript-react-apollo
のみ。
今回 install された version はこちら↓
"@graphql-codegen/typescript": "^2.4.3",
"@graphql-codegen/typescript-operations": "^2.2.4",
"@graphql-codegen/typescript-react-apollo": "^3.2.4",
2. Configure the plugin
次は codegen.yml
の設定値を更新する。
@graphql-codegen/typescript-react-apollo
を追加し、config.withHooks を true に設定するだけでOK。
こんな感じ↓
schema: http://my-graphql-api.com/graphql
documents: './src/**/*.tsx'
generates:
graphql/generated.ts:
plugins:
- typescript
- typescript-operations
- typescript-react-apollo
config:
withHooks: true
3. Run the codegen and update your code
以上でセットアップは完了! codegen を実行する。
以下の query operation から自動生成すると、
query Posts {
posts {
id
title
content
}
}
下のようなコードが作成される。
export type PostsQueryVariables = Exact<{ [key: string]: never; }>;
export type PostsQuery = { __typename?: 'Query', posts?: Array<{ __typename?: 'Post', id: string, title: string, content: string } | null> | null };
export const PostsDocument = gql`
query Posts {
posts {
id
title
content
}
}
`;
/**
* __usePostsQuery__
*
* To run a query within a React component, call `usePostsQuery` and pass it any options that fit your needs.
* When your component renders, `usePostsQuery` returns an object from Apollo Client that contains loading, error, and data properties
* you can use to render your UI.
*
* @param baseOptions options that will be passed into the query, supported options are listed on: https://www.apollographql.com/docs/react/api/react-hooks/#options;
*
* @example
* const { data, loading, error } = usePostsQuery({
* variables: {
* },
* });
*/
export function usePostsQuery(baseOptions?: Apollo.QueryHookOptions<PostsQuery, PostsQueryVariables>) {
const options = {...defaultOptions, ...baseOptions}
return Apollo.useQuery<PostsQuery, PostsQueryVariables>(PostsDocument, options);
}
export function usePostsLazyQuery(baseOptions?: Apollo.LazyQueryHookOptions<PostsQuery, PostsQueryVariables>) {
const options = {...defaultOptions, ...baseOptions}
return Apollo.useLazyQuery<PostsQuery, PostsQueryVariables>(PostsDocument, options);
}
export type PostsQueryHookResult = ReturnType<typeof usePostsQuery>;
export type PostsLazyQueryHookResult = ReturnType<typeof usePostsLazyQuery>;
export type PostsQueryResult = Apollo.QueryResult<PostsQuery, PostsQueryVariables>;
GraphqlDocument とそのデータ型も自動生成されていることがわかる。@graphql-codegen/typescript-react-apollo
を入れれば、@graphql-codegen/typed-document-node
は必要ないみたい。
実際に使ってみる
import { usePostsQuery } from './graphql/generated';
const Posts = () => {
const { data } = usePostsQuery();
// ...
}
型補完効いている!素晴らしい!
今回の project では Apollo Client を利用しているため、Apollo Client 向けのセットアップを行ったが、GraphQL Code Generator は React Query や URQL などの GraphQL Client のメジャーどころはカバーしているので、今後も利用していきたい。