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