GraphQL × TypeScript × Zod:Code Generator を活用した型安全な API 開発とスキーマ管理
はじめに
GraphQL を活用した開発において、スキーマと型の管理は非常に重要です。特に、バックエンドとフロントエンドの型を統一し、API の変更を適切に管理することは、開発の効率化とバグの削減につながります。本記事では、GraphQL Code Generator を中心に TypeScript, Zod, GraphQL SDL などの技術を組み合わせ、型安全な API 開発のためのベストプラクティスを紹介します。スキーマ駆動開発のフローを確立し、スキーマ管理やレスポンスバリデーション、API ドキュメントの自動生成、API テストの自動化までを一貫して解説します。
GraphQL を導入したものの、「スキーマ変更の管理が難しい」「フロントエンドで型の不整合が発生する」「レスポンスのバリデーションをどうするべきかわからない」といった課題を感じている方に向けて、具体的な解決策を提供します。
GraphQL Code Generator の導入と型定義の自動生成
GraphQL Code Generator とは?
GraphQL Code Generator は、GraphQL スキーマから TypeScript 型やコードを自動生成するツールです。これにより、フロントエンドとバックエンドでの型の不整合を防ぎ、開発効率を向上できます。
メリット
まず、GraphQL Code Generator を利用する主な目的は、「スキーマから自動生成される型定義を活用し、フロントエンドやバックエンドの実装を効率良く進める」 ことにあります。
- スキーマを変更すれば自動で型定義が更新される
- TypeScript と連携して、型安全性を高められる
- フロントエンド・バックエンド両者の実装が常にスキーマと一致する状態になる
特にチーム開発や大規模プロジェクトでは、型定義の自動生成を取り入れることで、作業効率・バグの減少ともに大きくメリットを得られます。
インストールと基本設定
以下のコマンドで @graphql-codegen/cli
をインストールします。
npm install --save-dev @graphql-codegen/cli
次に、必要なプラグインを追加します。TypeScript の型定義を生成する場合は、以下のプラグインをインストールします。
npm install --save-dev @graphql-codegen/typescript @graphql-codegen/typescript-operations @graphql-codegen/typescript-react-apollo
まず、GraphQL のスキーマを schema.graphql
に定義します。
type Author {
id: Int!
firstName: String!
lastName: String!
posts(findTitle: String): [Post]
}
type Post {
id: Int!
title: String!
author: Author
}
type Query {
posts: [Post]
}
ポイント
- これが サーバーのスキーマ定義 であり、この情報をもとに型定義が生成されます。
仮にGraphQL Code Generator を使っていなかった場合に、クライアントサイドでGraphQLにアクセスするとしたら下記のような書き方になります。
import { request, gql } from 'graphql-request'
import { useQuery } from '@tanstack/react-query'
interface PostsQuery {
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<PostsQuery>('posts', async () => {
const { posts } = await request(endpoint, postsQueryDocument)
return posts
})
}
interface PostsQuery {
posts: {
id: string
title: string
author?: {
id: string
firstName: string
lastName: string
}
}[]
}
このようにuseQuery
のレスポンスの型を事前に用意した上でデータ取得を行う必要があります。
この型定義を省略できるのがGraphQL Code Generatorの役割となります。
設定ファイル codegen.ts
を作成し、スキーマと対象となる GraphQL の操作を指定します。
import type { CodegenConfig } from '@graphql-codegen/cli'
const config: CodegenConfig = {
schema: 'https://localhost:4000/graphql',
documents: ['src/**/*.tsx'],
generates: {
'./src/gql/': {
preset: 'client',
}
}
}
export default config
次に、以下のコマンドを実行すると、型定義が自動生成されます。
npx graphql-codegen
すると下記のような形でデータを取得することが可能となります。
import { request } from 'graphql-request'
import { useQuery } from '@tanstack/react-query'
import { graphql } from './gql/gql'
const postsQueryDocument = graphql(/* GraphQL */ `
query Posts {
posts {
id
title
author {
id
firstName
lastName
}
}
}
`)
const Posts = () => {
const { data } = useQuery<PostsQuery>('posts', async () => {
const { posts } = await request(endpoint, postsQueryDocument)
return posts
})
}
このようにレスポンスの型を作らずともスキーマ定義から自動生成された型を使ってデータ取得が可能となります。
GraphQLのスキーマ定義とレスポンス用の(TypeScriptの)型定義をそれぞれ作っていた場合だと、定義の変更の際に両方修正する必要があります。
また状況を把握していない開発者が更新した場合に2つの定義に齟齬が発生する可能性もありデータ取得が失敗する恐れもあります。
そのような観点からも一元的に管理するのが望ましいと考えられます。
スキーマ駆動開発(GraphQL SDL ベースでの開発フロー確立)
スキーマ駆動開発(SDD)とは?
スキーマ駆動開発(SDD: Schema-Driven Development)とは、API の仕様を GraphQL のスキーマ定義(SDL: Schema Definition Language)を基盤に設計・開発を進める手法 です。
従来の REST API では、API 仕様書を別途作成し、フロントエンドとバックエンド間で共有する必要がありました。しかし、GraphQL ではスキーマがそのまま API の仕様となるため、開発の進行がスムーズになります。
メリット
- 仕様の明確化
スキーマがそのまま API 仕様となるため、フロントエンド / バックエンド間で仕様の認識相違が起きづらくなります。 - 自動ドキュメント化
GraphQL Playground や Apollo Studio などを使えば、スキーマ定義から自動的にドキュメントを生成でき、API の利用者が理解しやすくなります。 - 変更点の検知が容易
スキーマに変更がある場合、実装との整合性チェックも自動で発生しやすくなるため、変更の影響範囲が明確になります。
このステップを踏むことで、チーム全体の作業効率も上がり、スムーズなコミュニケーションとプロジェクト運営を実現できます。
開発フロー
スキーマ定義作成
type Author {
id: Int!
firstName: String!
lastName: String!
}
type Post {
id: Int!
title: String!
author: Author
}
type Query {
posts: [Post] # 単一の投稿を取得する
post(id: ID!): Post # 単一の投稿を取得する
}
このスキーマが API のベースとして機能し、フロントエンド・バックエンド間での共通認識となります。
4. バックエンド実装
スキーマから生成した TypeScript 型を活用して、バックエンドのリゾルバを実装します。
メリット
- スキーマが API の仕様書になるため、開発の方向性がブレない
- 実装がスキーマに沿っているかを保証できる
リゾルバの定義
// ダミーデータ
const posts = [
{ id: 1, title: "GraphQL Introduction", authorId: 1 },
{ id: 2, title: "Advanced GraphQL", authorId: 1 },
{ id: 3, title: "GraphQL with Apollo", authorId: 2 },
];
export const resolvers = {
Query: {
// すべての投稿を取得
posts: () => posts,
// IDで特定の投稿を取得
post: (_parent: any, args: { id: number }) =>
posts.find((post) => post.id === args.id),
},
};
GraphQLスキーマ定義を gql
(GraphQL タグ)としてパースします。
import { readFileSync } from "fs";
import { gql } from "graphql-tag";
import path from "path";
const schemaPath = path.resolve(process.cwd(), "../packages/graphql/schema/post.graphql");
const typeDefs = gql(readFileSync(schemaPath, "utf-8"));
export { typeDefs };
最後に、GraphQL サーバー (server) を Express に組み込んで起動します。
import express from "express";
import cors from "cors";
import { ApolloServer } from '@apollo/server';
import { expressMiddleware } from '@apollo/server/express4';
import { resolvers } from './graphql/resolvers';
import { typeDefs } from "./graphql/type";
const server = new ApolloServer({ typeDefs, resolvers });
const app = express();
const PORT = process.env.PORT || 4000;
const startServer = async () => {
await server.start();
app.use(
'/graphql',
cors(),
express.json(),
expressMiddleware(server)
);
app.listen(PORT, () => {
console.log('GraphQL server is running at http://localhost:4000/graphql');
});
};
startServer();
スキーマを基に TypeScript 型を自動生成
GraphQL のスキーマを基に GraphQL Code Generatorを使ってTypeScript の型を自動生成 することで、型安全な開発を実現します。
メリット
- API 変更時に型エラーが発生するため、修正漏れを防げる
- クライアント側の開発がより安全になる
GraphQL Code Generator (@graphql-codegen/cli
) の設定ファイル を作成し、
GraphQL のスキーマとクエリから 型付きの TypeScript コードを自動生成するための設定を行います。
import { CodegenConfig } from '@graphql-codegen/cli';
const config: CodegenConfig = {
schema: '../packages/graphql/schema/**/*.graphql',
generates: {
"generated/graphql.ts": {
plugins: [
'typescript',
'typescript-operations',
],
},
}
};
export default config;
TypeScriptの型が生成されます。
export type Maybe<T> = T | null;
export type InputMaybe<T> = Maybe<T>;
export type Exact<T extends { [key: string]: unknown }> = { [K in keyof T]: T[K] };
export type MakeOptional<T, K extends keyof T> = Omit<T, K> & { [SubKey in K]?: Maybe<T[SubKey]> };
export type MakeMaybe<T, K extends keyof T> = Omit<T, K> & { [SubKey in K]: Maybe<T[SubKey]> };
export type MakeEmpty<T extends { [key: string]: unknown }, K extends keyof T> = { [_ in K]?: never };
export type Incremental<T> = T | { [P in keyof T]?: P extends ' $fragmentName' | '__typename' ? T[P] : never };
/** All built-in and custom scalars, mapped to their actual values */
export type Scalars = {
ID: { input: string; output: string; }
String: { input: string; output: string; }
Boolean: { input: boolean; output: boolean; }
Int: { input: number; output: number; }
Float: { input: number; output: number; }
};
export type Author = {
__typename?: 'Author';
firstName: Scalars['String']['output'];
id: Scalars['Int']['output'];
lastName: Scalars['String']['output'];
posts?: Maybe<Array<Maybe<Post>>>;
};
export type AuthorPostsArgs = {
findTitle?: InputMaybe<Scalars['String']['input']>;
};
export type Post = {
__typename?: 'Post';
author?: Maybe<Author>;
id: Scalars['Int']['output'];
title: Scalars['String']['output'];
};
export type Query = {
__typename?: 'Query';
post?: Maybe<Post>;
posts?: Maybe<Array<Maybe<Post>>>;
};
export type QueryPostArgs = {
id: Scalars['ID']['input'];
};
フロントエンド実装
スキーマから生成した TypeScript 型を活用して、フロントエンド側で GraphQL クエリを記述します。
メリット
- API 仕様と実装のズレを防ぐ
- スキーマ変更が型に反映されるため、型エラーで検知しやすい
まずはGraphQLクエリを作成します。
query GetPosts {
posts {
id
title
author {
firstName
lastName
}
}
}
Code Generatorのconfigを設定変更します。
import { CodegenConfig } from '@graphql-codegen/cli';
const config: CodegenConfig = {
schema: '../packages/graphql/schema/**/*.graphql',
documents: '../packages/graphql/operations/**/*.graphql',
generates: {
"generated/graphql.ts": {
plugins: [
'typescript',
'typescript-operations',
'typescript-graphql-request',
],
},
}
};
export default config;
すると新たにクエリに関する定義と戻り値が用意され、フロントエンドで使うことができます。
export type GetPostsQuery = {
__typename?: 'Query',
posts?: Array<{
__typename?: 'Post',
id: number,
title: string,
author?: {
__typename?: 'Author',
firstName: string,
lastName: string
} | null
} | null> | null
};
export const GetPostsDocument = gql`
query GetPosts {
posts {
id
title
author {
firstName
lastName
}
}
}
`;
export type SdkFunctionWrapper = <T>(action: (requestHeaders?:Record<string, string>) => Promise<T>, operationName: string, operationType?: string, variables?: any) => Promise<T>;
const defaultWrapper: SdkFunctionWrapper = (action, _operationName, _operationType, _variables) => action();
export function getSdk(client: GraphQLClient, withWrapper: SdkFunctionWrapper = defaultWrapper) {
return {
GetPosts(variables?: GetPostsQueryVariables, requestHeaders?: GraphQLClientRequestHeaders): Promise<GetPostsQuery> {
return withWrapper((wrappedRequestHeaders) => client.request<GetPostsQuery>(GetPostsDocument, variables, {...requestHeaders, ...wrappedRequestHeaders}), 'GetPosts', 'query', variables);
}
};
}
export type Sdk = ReturnType<typeof getSdk>;
import { GraphQLClient } from "graphql-request";
import { getSdk } from "../generated/graphql";
const client = new GraphQLClient("http://localhost:4000/graphql");
const sdk = getSdk(client);
export async function getPost() {
const response = await sdk.GetPosts();
return response.posts
}
import { useEffect, useState } from "react";
import { GetPostsQuery } from "../generated/graphql";
import { getPosts } from "./service";
function App() {
const [posts, setPosts] = useState<GetPostsQuery["posts"] | null>(null);
useEffect(() => {
getPosts()
.then((data) => {
setPosts(data);
})
.catch((error) => {
console.error(error);
});
}, []);
return (
<div>
<h1>React + Express</h1>
{posts === null || posts === undefined ? (
<p>Loading...</p>
) : posts.length === 0 ? (
<p>No posts found.</p>
) : (
<ul>
{posts.map((post) => (
<li key={post?.id}>
<h2>{post?.title}</h2>
<p>Author: {post?.author?.firstName} {post?.author?.lastName}</p>
</li>
))}
</ul>
)}
</div>
);
}
export default App;
GraphQL のスキーマ管理(変更履歴の追跡・バージョン管理)
GraphQL のスキーマは、フロントエンドとバックエンドの通信を規定する契約のようなものです。そのため、スキーマに変更が加わると、両者の整合性が崩れる可能性があります。
特に、破壊的変更(Breaking Changes) があると、クライアント側のコードが動かなくなるリスクがあるため、スキーマのバージョン管理や変更履歴の追跡が重要です。
Git を活用したスキーマのバージョン管理
スキーマファイルを Git リポジトリで管理 し、変更履歴を追跡することで、いつ・どのような変更が行われたかを把握できます。
またGitHub では、GitHub Actions を活用して、schema.graphql に変更があった場合に PR に自動でラベルを付与 することができます。
.github/labeler.yml
を作成(スキーマ変更を検知する設定)
1. schema-change:
- "apps/packages/graphql/schema/**/*.graphql"
- スキーマファイルの変更のみを検知します。
2. GitHub Actions ワークフローを作成(PR にラベルを付与) .github/workflows/label-schema-changes.yml
name: "Add label for GraphQL schema changes"
on:
pull_request:
permissions:
pull-requests: write
contents: read
jobs:
label:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- name: Apply labels
uses: actions/labeler@v4
with:
repo-token: "${{ secrets.GITHUB_TOKEN }}"
apps/packages/graphql/schema/**/*.graphql
に変更があった場合、PR にschema-change
というラベルが自動で付きます。
PRを作成すると
- ①Labelを付与するGitHub Actions ワークフローが実行され
- ②Labelsに
schema-change
がセットされます。
labelで知らせるだけでなくGitHub Actions ワークフローのslack連携を使用すると通知を行うなども可能です。
スキーマのマイグレーション(Schema Migration)
GraphQL スキーマを直接変更するのではなく、段階的な移行 を行うことで、クライアントへの影響を最小限に抑えることができます。
安全なスキーマ変更の流れ
- 非破壊的変更(Backward Compatible)を優先
- フィールドの追加
- デフォルト値の変更
- 破壊的変更が必要な場合は Deprecation(非推奨化)
@deprecated
ディレクティブを使って、古いフィールドを非推奨にする- クライアント側で対応が完了した後に削除する
例)
type Post {
id: Int!
title: String!
description: String @deprecated(reason: "Use 'excerpt' instead.")
author: Author
}
このように @deprecated
をつけることで、クライアントに「このフィールドは将来的に削除される」ということを通知できます。
GraphQL Playgroundでクエリを作成する際にも非推奨であることが表示され開発者に知らせることが可能です。
バックエンドのレスポンスバリデーション(Zod などを活用)
バックエンドのレスポンスバリデーションとは、API からクライアントへ返されるデータが期待した形式や構造になっているかを検証するプロセスです。適切なバリデーションを行うことで、フロントエンドでのエラー防止やセキュリティ強化につながります。
なぜレスポンスバリデーションが必要なのか
-
データ整合性の確保
バックエンドが予期せぬデータを返す可能性があるため、フロントエンドが誤動作しないようにするために必要です。 -
セキュリティリスクの軽減
不正なデータがレスポンスに含まれてしまうと、XSS やデータ改ざんといったセキュリティリスクが発生します。 -
バグの早期発見
API の変更が原因でレスポンスの構造が変わった場合、バリデーションによって問題を即座に検知できます。
レスポンスバリデーションの実装方法
- スキーマバリデーションを導入する
JSON Schema などを使用して、レスポンスの構造を定義し、それに基づいたバリデーションを行うのが一般的です。
例: Zod を使用したバリデーション(Node.js)
import { z } from 'zod';
const userSchema = z.object({
id: z.number(),
name: z.string(),
email: z.string().email(),
});
const validateResponse = (data: any) => {
const result = userSchema.safeParse(data);
if (!result.success) {
console.error("Invalid response data:", result.error.format());
throw new Error("Response validation failed");
}
return result.data;
};
- バックエンド側でバリデーションを実装する
バックエンドのレスポンスを生成する際に、データの型や値のチェックを行うことで、不正なデータを返さないようにします。
Express でのレスポンスバリデーション例
import express from 'express';
import { z } from 'zod';
const app = express();
const responseSchema = z.object({
success: z.boolean(),
data: z.object({
id: z.number(),
name: z.string(),
}),
});
app.get('/user', (req, res) => {
const responseData = {
success: true,
data: { id: 1, name: "Taro" },
};
const validationResult = responseSchema.safeParse(responseData);
if (!validationResult.success) {
return res.status(500).json({ error: "Invalid response format" });
}
res.json(responseData);
});
app.listen(3000, () => console.log("Server running on port 3000"));
フェッチ時の型チェック強化(フロント側での不整合防止)
フロントエンド開発では、APIから取得したデータの型が期待通りでない場合に、アプリケーションの挙動が不安定になることがあります。本記事では、フェッチ時の型チェックを強化し、フロントエンド側での不整合を防ぐための方法を解説します。
APIレスポンスの型定義
TypeScriptを活用して、APIから返されるデータの型を定義することで、型安全な開発が可能になります。
interface User {
id: number;
name: string;
email: string;
}
async function fetchUser(): Promise<User> {
const response = await fetch("https://api.example.com/user");
const data = await response.json();
return data; // 型チェックを強化するためにバリデーションを追加
}
型アサーションを避ける
型アサーション (as Type) を多用すると、実際には不整合なデータが渡された場合でもコンパイルエラーを回避してしまうため、適切な型チェックが機能しません。
async function fetchUser(): Promise<User> {
const response = await fetch("https://api.example.com/user");
const data = await response.json();
return data as User; // ⚠️ 型アサーションのみだと不正なデータが入りうる
}
Zodを活用した型安全なデータチェック
Zodなどのスキーマバリデーションライブラリを活用すると、APIレスポンスの構造を厳密に検証できます。
import { z } from "zod";
const UserSchema = z.object({
id: z.number(),
name: z.string(),
email: z.string().email(),
});
type User = z.infer<typeof UserSchema>;
async function fetchUser(): Promise<User> {
const response = await fetch("https://api.example.com/user");
const data = await response.json();
return UserSchema.parse(data); // ここで型チェックを実施
}
型ガードを活用した手動チェック
バリデーションライブラリを使わずに、手動で型チェックを行うことも可能です。
function isUser(data: unknown): data is User {
return (
typeof data === "object" && data !== null &&
"id" in data && typeof (data as any).id === "number" &&
"name" in data && typeof (data as any).name === "string" &&
"email" in data && typeof (data as any).email === "string"
);
}
async function fetchUser(): Promise<User> {
const response = await fetch("https://api.example.com/user");
const data = await response.json();
if (!isUser(data)) {
throw new Error("Invalid API response");
}
return data;
}
GraphQL Code Generator を活用した型安全な開発
import { gql } from "graphql-tag";
import { request } from "graphql-request";
import { UserQuery } from "@generated/graphql";
const GET_USER = gql`
query getUser($id: ID!) {
user(id: $id) {
id
name
email
}
}
`;
async function fetchUser(id: string): Promise<UserQuery> {
const response = await request("/graphql", GET_USER, { id });
return response;
}
このように、GraphQL の型を適用することで、API レスポンスの型を保証できます。
API ドキュメントの自動生成
API の開発において、ドキュメントの整備とテストの自動化は重要な要素です。GraphQL Playground や Swagger を活用した API ドキュメントの自動生成、および Mock サーバーを利用した API テストの自動化について解説します。
GraphQL Playground を活用した API ドキュメント
GraphQL では、スキーマ定義を基に動的に API ドキュメントを生成できます。GraphQL Playground は、API のエンドポイントを視覚的に確認でき、スキーマを即時にドキュメント化する便利なツールです。
- Playground を有効化するには以下のように設定します。
import { ApolloServer, gql } from 'apollo-server';
const typeDefs = gql`
type Query {
hello: String
}
`;
const resolvers = {
Query: {
hello: () => 'Hello, world!',
},
};
const server = new ApolloServer({ typeDefs, resolvers });
server.listen().then(({ url }) => {
console.log(`Server ready at ${url}`);
});
-
サーバーを起動すると、
http://localhost:4000
で Playground にアクセス可能になります。 -
GraphQL スキーマの変更を即座に反映し、開発者向けの API ドキュメントを自動生成できます。
下記のようにフィールド情報が表示され、サンプルのクエリを作成する際にはコード補完もされます。
Swagger を利用した REST API ドキュメント
REST API のドキュメント自動生成には Swagger(OpenAPI)を活用します。
- Express ベースの API に
swagger-jsdoc
とswagger-ui-express
を追加します。
npm install swagger-jsdoc swagger-ui-express
- Swagger 設定を追加します。
import express from 'express';
import swaggerJsdoc from 'swagger-jsdoc';
import swaggerUi from 'swagger-ui-express';
const app = express();
const swaggerOptions = {
definition: {
openapi: '3.0.0',
info: {
title: 'Sample API',
version: '1.0.0',
},
},
apis: ['./routes/*.js'],
};
const swaggerDocs = swaggerJsdoc(swaggerOptions);
app.use('/api-docs', swaggerUi.serve, swaggerUi.setup(swaggerDocs));
app.listen(3000, () => console.log('Server running on port 3000'));
http://localhost:3000/api-docs
にアクセスすると、Swagger UI で API ドキュメントが確認できます。
API テストの自動化(Mock サーバーの活用)
API のテストを効率的に行うために、Mock サーバーを活用します。json-server
や GraphQL の @graphql-tools/mock
を利用すると、バックエンドの開発前でもフロントエンドの開発・テストを進めることができます。
JSON Server を使った Mock REST API
json-server
は、シンプルな JSON ファイルをもとに REST API を提供できる便利なツールです。これにより、バックエンドの実装が完了していなくても、フロントエンドの開発やテストを進めることができます。
-
json-server
をインストールします。npm install -g json-server
-
db.json
を作成し、ダミーデータを用意します。{ "users": [ { "id": 1, "name": "Alice" }, { "id": 2, "name": "Bob" } ] }
-
json-server
を起動します。json-server --watch db.json --port 3001
-
http://localhost:3001/users
にアクセスすると、Mock API が動作していることを確認できます。
なお、json-server
には以下のようなカスタマイズ機能があります。
-
カスタムルートの設定:
routes.json
を作成し、エンドポイントをカスタマイズできます。{ "/api/users": "/users" }
-
json-server
をExpress
のようにカスタマイズするためのものです。通常、json-server
は CLI から簡単に使えますが、Express
のように拡張することで、リクエストをより柔軟に処理できます。
const jsonServer = require('json-server');
const server = jsonServer.create(); // JSON Server のインスタンスを作成
const router = jsonServer.router('db.json'); // db.json をもとにルーティングを生成
const middlewares = jsonServer.defaults(); // JSON Server のデフォルトミドルウェア(CORS, ロギング, JSON パースなど)を適用
server.use(middlewares); // ミドルウェア適用
server.use((req, res, next) => {
console.log('Request received:', req.method, req.url); // リクエストログを出力
next(); // 次のミドルウェアへ処理を渡す
});
server.use(router); // ルーターを適用
server.listen(3001, () => {
console.log('JSON Server is running on port 3001');
});
ポイント
- すべてのリクエストをコンソールに出力することで、デバッグしやすくなる。
json-server
の標準ログに加え、リクエストの詳細な制御が可能。
server.use('/users', (req, res, next) => {
req.query.limit = 10; // クエリパラメータを強制的に追加
next();
});
ポイント
/users
にアクセスしたときにリクエストのデータを変更することも可能。
router.render = (req, res) => {
res.json({
success: true,
data: res.locals.data
});
};
json-server
のデフォルトレスポンスを変更して、カスタムレスポンスを返すことも可能。- すべてのレスポンスに
success: true
を追加できる。
GraphQL Mock サーバーの構築
@graphql-tools/mock
を使用して GraphQL Mock サーバーを構築します。
npm install @graphql-tools/mock @graphql-tools/schema graphql-tag
- Mock API の設定を追加します。
import { makeExecutableSchema } from '@graphql-tools/schema';
import { addMocksToSchema } from '@graphql-tools/mock';
import { graphql } from 'graphql';
const typeDefs = `
type User {
id: ID!
name: String!
}
type Query {
users: [User]
}
`;
const schema = makeExecutableSchema({ typeDefs });
const mockedSchema = addMocksToSchema({ schema });
graphql(mockedSchema, '{ users { id name } }').then((result) =>
console.log(JSON.stringify(result, null, 2))
);
- スキーマに基づいた Mock API が即座に生成され、テストが可能になります。
さいごに
GraphQL Code Generator を活用することで、GraphQL のスキーマ管理や型定義の自動生成を効率化し、バックエンドとフロントエンドの型の不整合を防ぐことができます。また、Zod を用いたレスポンスバリデーション や フェッチ時の型チェック強化 によって、安全なデータの受け渡しを実現できます。さらに、API ドキュメントの自動生成や Mock サーバーを活用した API テストの自動化により、開発の効率を向上させることが可能です。
本記事で紹介した手法を活用することで、GraphQL の強みを最大限に活かした型安全な API 開発 が実現できます。ぜひ、プロジェクトに適用し、よりスムーズな開発体験を目指してみてください。
関連する技術ブログ
ExpressとMongoDBで簡単にWeb APIを構築する方法【TypeScript対応】
本記事では、MongoDB Atlasを活用してREST APIを構築する方法を、初心者の方にも分かりやすいステップで解説します。プロジェクトの初期設定からMongoDBの接続設定、Expressを使用したルートの作成、さらにTypeScriptを用いた型安全な実装まで、実践的なサンプルコードを交えて丁寧に説明します。
shinagawa-web.com
Express(+TypeScript)入門ガイド: Webアプリケーションを素早く構築する方法
Node.jsでWebアプリケーションを構築するための軽量フレームワーク、Expressの基本的な使い方を解説。シンプルなサーバー設定からルーティング、ミドルウェアの活用方法、TypeScriptでの開発環境構築まで、実践的なコード例とともに学べます。
shinagawa-web.com
React のリファクタリング完全ガイド:モジュール化・レンダリング最適化・設計パターン適用でコードを改善
フロントエンド開発において、可読性が低いコードやパフォーマンスの課題を抱えていませんか?本記事では、React を用いたフロントエンドのリファクタリング手法を具体的なコード例とともに解説します。命名規則の統一や関数分割による可読性向上、共通処理のモジュール化によるコードの整理、関心の分離に基づいたコンポーネント設計の最適化を実践。また、useMemo / useCallback / React.memo を活用したレンダリングの最適化、Promise.all や useQuery の適切な適用による非同期処理の最適化など、パフォーマンス改善にも焦点を当てます。さらに、クリーンアーキテクチャやリポジトリパターンの導入、TypeScript による型安全性の強化、依存関係の整理まで幅広くカバー。リファクタリングを計画的に進める方法も紹介し、スムーズな適用を支援します。より読みやすく、保守しやすいコードへと進化させるための実践的なアプローチをご紹介します。
shinagawa-web.com
JestとTypeScriptで始めるテスト自動化:基本設定から型安全なテストの書き方まで徹底解説
JestとTypeScriptを使ったテスト自動化の基本を学びたい方へ。環境のセットアップ方法、型安全なテストを書くメリット、コードの信頼性を高める実践的なテクニックを初心者向けに丁寧に解説します。テストカバレッジの活用で、品質の高い開発を目指しましょう。
shinagawa-web.com
ESLint / Prettier 導入ガイド: Husky, CI/CD 統合, コード品質の可視化まで徹底解説
開発チームでコードの品質を統一するために、Linter(ESLint)と Formatter(Prettier)は欠かせません。Linter はコードの構文やスタイルの問題を検出し、Formatter はコードの整形を統一します。本記事では、9つの取り組みについて詳しく解説します。
shinagawa-web.com
フロントエンド開発に役立つモックサーバー構築:@graphql-tools/mock と Faker を使った実践ガイド
フロントエンド開発を先行させるために、バックエンドが未完成でもモックサーバーを立ち上げる方法を解説。@graphql-tools/mock と Faker を使用して、実際のデータに近い動作をシミュレートします。
shinagawa-web.com
Mock Service Worker (MSW) を使ったAPIモックとテストの効率化
MSW(Mock Service Worker)を使用して、フロントエンド開発やテスト環境でのAPIモックを効率的に行う方法を解説します。Mock Service Workerの基本的な使い方から、Jestテストでの活用方法、さらにテストを簡単にするための設定手順を紹介します。
shinagawa-web.com
Next.jsとAuth.jsで認証機能を実装するチュートリアル
Next.jsでアプリケーションを作る時に必要となる認証機能をどのように実装するかをご紹介する記事となります。アカウント登録から始まり、ログイン、ログアウト、ページごとのアクセス制御、OAuth、二要素認証、パスワードリセットなど認証に関連する様々な機能をコードベースでご紹介します。
shinagawa-web.com
弊社の技術支援サービス
無駄なコストを削減し、投資対効果を最大化する
クラウド費用の高騰、不要なSaaSの乱立、開発工数の増加――これらの課題に悩んでいませんか?本サービスでは、クラウドコストの最適化、開発効率向上、技術選定の最適化 を通じて、単なるコスト削減ではなく、ROIを最大化する最適解 をご提案します。
shinagawa-web.com
最新技術の導入・検証を支援するPoCサービス
Remix、React Server Components、TypeScript移行、クラウドサービス比較、マイクロサービス、サーバーレス、デザインシステムなど、最新技術のPoC(概念実証)を通じて、最適な技術選定と導入を支援します。貴社の開発課題に合わせた検証・実装で、ビジネスの成長を加速させます。
shinagawa-web.com
開発生産性を最大化するための支援サービス
開発チームの生産性向上、コードの品質管理、インフラの最適化まで、様々な側面からサポートします。コードベースのリファクタリングから、テスト自動化、オンボーディング強化まで、プロジェクトの成功に必要なすべての支援を提供。御社の開発現場が効率的に機能するように、技術的な障害を取り除き、スムーズな開発を実現します。
shinagawa-web.com
開発品質向上支援 – 効率的で安定したプロダクトを実現
フロントエンドからバックエンド、データベースまで、開発プロセス全体を最適化し、安定したプロダクト作りをサポートします。コードレビューの仕組み、型定義の強化、E2Eテスト環境の構築など、開発の各ステップにおけるベストプラクティスを導入することで、より効率的でバグの少ない、そしてユーザー満足度の高いサービス提供を支援します。
shinagawa-web.com
Webアプリのセキュリティ強化支援
Webアプリの脆弱性対策からインフラのセキュリティ強化まで、包括的なセキュリティ支援を提供。OWASP Top 10対策、JWT認証の最適化、APIのアクセス制御、依存パッケージの監査、セキュアコーディングの標準化など、実践的なアプローチで開発現場の安全性を向上させます。
shinagawa-web.com
目次
お問い合わせ