GraphQL、型定義をスキーマから自動生成するところまで試してみた。
やってみて気づいたこととして、自動生成する型定義はサーバとクライアントの2種類があるということ。それぞれ必要。
サーバ
サーバの方はschema.graphqlというようなスキーマ定義ファイルがあれば生成できる。
npm install -D @graphql-codegen/cli @graphql-codegen/typescript @graphql-codegen/typescript-resolvers
公式はyamlでConfigを作成していたが、tsでもConfigは作成できる。
import type { CodegenConfig } from '@graphql-codegen/cli'; const config: CodegenConfig = { schema: "./src/schema.graphql", generates: { "./src/__generated__/resolvers-types.ts": { plugins: [ "typescript", "typescript-resolvers", ], config: { useIndexSignature: true, contextType: "../index#MyContext", }, }, }, overwrite: true, }; export default config;
このファイルをcodegen-server.tsと保存してCLIでgenerateする。
npx graphql-codegen --config codegen-server.ts
これで./src/__generated__/resolvers-types.ts
に型定義が出力されるので、importして、Resolverの型を置き換えてやればよい。
最小限のコードだけ示すと以下。
import { Resolvers } from './__generated__/resolvers-types'; const resolvers: Resolvers = { Query: { ... } };
もちろん、スキーマ中で定義した型もimportできる。
Apollo-serverのドキュメントを参考にした。 Generating types from a GraphQL schema - Apollo GraphQL Docs
クライアント
GraphQLクライアントでは、クエリ毎に取得できるデータは異なる。そのため、クエリ毎に型定義が必要になる。
例えば以下のコードでは、gqlで宣言しているクエリが対象となる。 クエリ名(ここでのGetBooks)は自動生成されるGraphQLの型定義でも利用されるため、クエリ毎にユニークな名前を付ける必要がある。
import { ApolloClient, InMemoryCache } from '@apollo/client/core'; import { gql } from '@apollo/client/core'; const query = gql(` query GetBooks { books { id title } } `); async function query() { const client = new ApolloClient({ uri: 'http://localhost:4000/', cache: new InMemoryCache(), }); const { data: { books } } = await client.query({ query }); books.map(book => { console.log({ book }); }) } void query();
クライアント用のConfigの定義は以下codegen-client.ts
とする。
サーバのときのConfig異なるのは対象スキーマ以外にdocumentsでtsファイルを指定している。(クエリの記述があるコードを指定する必要がある)
presetでのclientを指定も必要。
import type { CodegenConfig } from '@graphql-codegen/cli'; const config: CodegenConfig = { schema: "./src/schema.graphql", documents: ['src/**/*.{ts,tsx}'], generates: { "./src/__generated__/": { preset: 'client', plugins: [], presetConfig: { gqlTagName: 'gql', }, }, }, ignoreNoDocuments: true, overwrite: true, }; export default config;
ここでは無難にApolloClientを使っておく。
自動生成対象となるクエリをgqlでDocumentNodeに変換してからclientのqueryに渡すようにしておく。そうするとcodegenを実行した際に必要な型定義が作成の対象となる様子。
型定義の自動生成はサーバと変わらない。以下で実行する。
npx graphql-codegen --config codegen-client.ts
自動生成後は、
@apollo/client/core
からimportしていたgql
を自動生成したgql
に置き換えれば、生成された型が効くようになる。
import { gql } from '@apollo/client/core';
import { gql } from '../src/__generated__/gql';
クライアントのドキュメントはちょっとみつけられなかったので。React用のドキュメントを参考にしつつやってみたという形。 Generating types from a GraphQL schema - Apollo GraphQL Docs