概要
本記事では Code Generator を活用した GraphQL × Nextjs の開発プラクティスについて紹介します。
Codegenとは
GraphQL Code Generator(codegen)
は、GraphQLスキーマとクエリからTypeScriptの型定義を自動生成するツールです。
手動で型を書く必要がなく、GraphQL
スキーマの変更に自動で追従できるため、型安全で保守性の高いアプリケーションを構築できます🙋♂️
セットアップ
パッケージのインストール
npm install --save-dev @graphql-codegen/cli @graphql-codegen/typescript @graphql-codegen/typescript-operations @graphql-codegen/typescript-document-nodes
codegen.yml の作成
codegen.yml
overwrite: true
schema: "http://localhost:5000/graphql"
documents: "src/**/*.graphql"
generates:
src/generated/graphql.ts:
plugins:
- typescript
- typescript-operations
- typed-document-node
config:
scalars:
ISO8601DateTime: string
package.jsonにスクリプト追加
package.json
{
"scripts": {
"codegen": "graphql-codegen --config codegen.yml",
"codegen:watch": "graphql-codegen --config codegen.yml --watch"
}
}
ワークフロー
ディレクトリ構成(推奨例)
src/
├── graphql/
├── queries/ # 実行するクエリファイルを格納
│ ├── getPosts.graphql
│ └── getPost.graphql
├── mutations/ # 実行するミューテーションファイルを格納
│ ├── createPost.graphql
│ └── updatePost.graphql
└── generated.ts # Codegenにより生成されるファイル
# 1. GraphQLクエリファイルを作成
# 例)src/graphql/queries/getPost.graphql...
# 2. 型を生成
npm run codegen
# 3. 生成された型を使用
import { GetPostQuery, GetPostDocument } from './generated'
開発フロー
GraphQLクエリの作成
src/graphql/queries/getPost.graphql
query GetPost($id: ID!, $first: Int!) {
published {
post(id: $id) {
id
title
content
}
}
}
型の生成
npm run codegen
# watch mode
npm run codegen:watch
生成された型の使用
import { GetPostDocument, GetPostQuery } from '@/generated/graphql';
export const getPost = async (id: string): Promise<GetPostQuery> => {
const { data } = await query({
query: GetPostDocument,
variables: { id }
});
return data;
};
Codegenによって生成される型と活用シチュエーション
1. Document型 - [QueryName]Document
用途: GraphQLクエリの実行時に使用
// 生成例
export const GetPostDocument = ...;
// 使用シチュエーション
const { data } = await client.query({
query: GetPostDocument, // ← 実行可能なクエリとして使用
variables: { id: "123" }
});
2. Query型 - [QueryName]Query
用途: クエリ結果の型安全な受け取り・処理
// 生成例
export type GetPostQuery = {
published: {
post: {
id: string;
title: string;
content: string;
} | null;
};
};
// 使用シチュエーション
const processPostData = (data: GetPostQuery) => {
const post = data.published.post;
if (post) {
console.log(post.title); // 型安全にアクセス
}
};
3. Variables型 - [QueryName]QueryVariables
用途: クエリ変数の型チェック
// 生成例
export type GetPostQueryVariables = {
id: string;
};
// 使用シチュエーション
const fetchPost = async (id: string) => {
const variables: GetPostQueryVariables = {
id
};
return await query({ query: GetPostDocument, variables });
};
4. Mutation型 - [MutationName]Mutation
用途: Mutation結果の型安全な処理
// 生成例
export type CreatePostMutation = {
createPost: {
id: string;
title: string;
success: boolean;
};
};
// 使用シチュエーション
const handleCreatePost = async () => {
const result = await mutate({ mutation: CreatePostDocument });
if (result.data) {
const newPost: CreatePostMutation = result.data;
console.log(`Created post: ${newPost.createPost.title}`);
}
};
5. MutationVariables型 - [MutationName]MutationVariables
用途: Mutation入力値の型チェック
// 生成例
export type CreatePostMutationVariables = {
title: string;
content: string;
tags?: string[];
};
// 使用シチュエーション
const createPost = async (postData: CreatePostMutationVariables) => {
// 入力値が型チェックされる
return await mutate({
mutation: CreatePostDocument,
variables: postData
});
};
6. Fragment型 - [FragmentName]Fragment
用途: 再利用可能なデータ構造の型定義
// GraphQLフラグメント
fragment PostSummary on Post {
id
title
publishedAt
}
// 生成例
export type PostSummaryFragment = {
id: string;
title: string;
publishedAt: string;
};
// 使用シチュエーション
const PostCard = ({ post }: { post: PostSummaryFragment }) => (
<div>
<h3>{post.title}</h3>
<time>{post.publishedAt}</time>
</div>
);
まとめ
便利ですね 👌
型生成を開発フローに組み込み、型安全なGraphQLアプリケーションを構築しましょう。