Zodスキーマで完全なAPIレスポンスを検証する
メタデータ、ページネーション、ネストされたデータを含む完全なREST APIレスポンスを包括的なZodバリデーションスキーマに変換する方法を学びます。
Advanced
詳細な説明
Zodでの実際のAPIレスポンス検証
本番環境のAPIレスポンスはデータだけではありません。ステータスコード、ページネーション情報、エラーエンベロープ、深くネストされたオブジェクトを含みます。Zodスキーマはレスポンス構造全体をランタイムで検証します。
JSON例
{
"status": "success",
"data": {
"users": [
{
"id": 1,
"name": "Alice",
"email": "alice@example.com",
"profile": {
"avatar": "https://cdn.example.com/alice.jpg",
"bio": "Full-stack developer"
}
}
],
"pagination": {
"page": 1,
"perPage": 20,
"total": 150,
"totalPages": 8
}
},
"requestId": "req_abc123"
}
生成されるZodスキーマ
import { z } from "zod";
const profileSchema = z.object({
avatar: z.string().url(),
bio: z.string(),
});
const userSchema = z.object({
id: z.number().int(),
name: z.string(),
email: z.string().email(),
profile: profileSchema,
});
const paginationSchema = z.object({
page: z.number().int().positive(),
perPage: z.number().int().positive(),
total: z.number().int().nonnegative(),
totalPages: z.number().int().nonnegative(),
});
const apiResponseSchema = z.object({
status: z.enum(["success", "error"]),
data: z.object({
users: z.array(userSchema),
pagination: paginationSchema,
}),
requestId: z.string(),
});
type ApiResponse = z.infer<typeof apiResponseSchema>;
ジェネリック化
function createPaginatedSchema<T extends z.ZodTypeAny>(itemSchema: T) {
return z.object({
status: z.enum(["success", "error"]),
data: z.object({
items: z.array(itemSchema),
pagination: paginationSchema,
}),
requestId: z.string(),
});
}
const userListSchema = createPaginatedSchema(userSchema);
const productListSchema = createPaginatedSchema(productSchema);
エラーレスポンスの処理
const errorSchema = z.object({
status: z.literal("error"),
error: z.object({
code: z.string(),
message: z.string(),
}),
requestId: z.string(),
});
const responseSchema = z.union([apiResponseSchema, errorSchema]);
fetchとの統合
async function fetchUsers(): Promise<ApiResponse> {
const res = await fetch("/api/users");
const json = await res.json();
return apiResponseSchema.parse(json);
// レスポンス形状が無効な場合ZodErrorをスロー
}
このパターンは、不正なデータがアプリケーションに伝播する前に、APIコントラクト違反を即座にキャッチします。
ユースケース
REST APIのフロントエンドクライアントライブラリを構築し、UIエラーの原因となる前にバックエンドのコントラクト違反をキャッチするために、すべてのレスポンスのランタイムバリデーションが必要な場合に使用します。