Nitroで、APIリクエストのデータをバリデーションする
こんにちは、合同会社Stegの keigo です。
本記事では、Nitro における API エンドポイントのバリデーション処理を、h3 が提供するバリデーションユーティリティを用いて効率的に実装する方法を紹介します。
クエリパラメータやリクエストボディのバリデーションを自前で実装すると、コードの冗長化や保守性の低下、エラーハンドリングのばらつきといった課題が生じることがあります。
今回紹介する方法は、これらの課題を解消し、シンプルかつ一貫性のあるバリデーション処理を実現するものです。
Nitroがサポートしているバリデーションユーティリティーについて
Nitroでは、h3が提供する以下3つのバリデーションユーティリティーをサポートしています。
getValidatedQuery
getValidatedRouterParams
readValidatedBody
バリデーションには、Zodやjoi、myzodなど、任意のバリデーションライブラリを使用します。
本記事では、Zodと組み合わせたAPIリクエストデータのバリデーションを紹介します。
getValidatedQuery
)
1. クエリパラメータのバリデーション (バリデーション未実装の例
まずは、フロントエンドから次のような GET リクエストが送信されると仮定します。
const getResult = await $fetch('/api', {
query: {
name: 'keigo',
age: 25,
},
});
バリデーションを実装していない場合、API エンドポイントは以下のように実装されるでしょう。
export default defineEventHandler(async (event) => {
const { name, age } = getQuery(event);
return `Hello, ${name}! You are ${age} years old.`;
});
この状態でリクエストが発火すると、以下のレスポンスが返されます。
Hello, keigo! You are 25 years old.
バリデーション実装の例
ここでは、次の条件を満たすバリデーションを実装します。
-
name
は文字列であること -
age
は数値であること
Zod を用いて、以下のように実装します。
import { z } from 'zod';
export default defineEventHandler(async (event) => {
const querySchema = z.object({
name: z.string(),
age: z.number({ coerce: true }).positive().int(),
});
const { name, age } = await getValidatedQuery(event, querySchema.parse);
return `Hello, ${name}! You are ${age} years old.`;
});
この実装では、getValidatedQuery
によりリクエストのクエリパラメータがスキーマに沿って検証され、不正な値が渡された場合は 400 エラーが返却されます。
例えば、age
に文字列が指定されると、以下のようなエラーレスポンスが生成されます。
getValidatedRouterParams
)
2. パスパラメータのバリデーション (バリデーション未実装の例
次に、以下のパスパラメータを持つ API エンドポイントを考えます。
/api/:id
フロントエンドからは以下の GET リクエストが送信されるとします。
const getResult = await $fetch('/api/123');
バリデーション未実装の場合、API エンドポイントは次のようになります。
export default defineEventHandler(async (event) => {
const { id } = getRouterParams(event);
return `Hello! id is ${id}!`;
});
この状態でリクエストが発火すると、以下のレスポンスが返されます。
Hello! id is 123!
バリデーション実装の例
ここでは、id
が数値であることを検証するため、次の条件を設定します。
-
id
は数値であること
Zod を用いて実装する例は以下の通りです。
import { z } from 'zod';
export default defineEventHandler(async (event) => {
const routerParamsSchema = z.object({
id: z.number().int().positive(),
});
const { id } = await getValidatedRouterParams(event, routerParamsSchema.parse);
return `Hello! id is ${id}!`;
});
この実装により、例えば id
に文字列が指定された場合、400 エラーが返却されるようになります。
readValidatedBody
)
3. リクエストボディのバリデーション (バリデーション未実装の例
次に、フロントエンドから以下のような POST リクエストが送信されるケースを考えます。
const postResult = await $fetch('/api', {
method: 'POST',
body: {
name: 'keigo',
age: 25,
},
});
バリデーション実装の例
バリデーションを行う場合、以下のように API エンドポイントを実装します。
import { z } from 'zod';
export default defineEventHandler(async (event) => {
const bodySchema = z.object({
name: z.string(),
age: z.number({ coerce: true }).positive().int(),
});
const { name, age } = await readValidatedBody(event, bodySchema.parse);
return {
message: `Hello ${name}! You are ${age} years old.`,
};
});
この実装により、リクエストボディの内容が指定したスキーマに沿って検証され、誤った値が送信された場合は 400 エラーが自動的に返却されます。
例えば、age
に文字列が指定された場合は、以下のようなエラーレスポンスとなります。
まとめ
本記事では、Nuxt Server(Nitro)において、h3 が提供するバリデーションユーティリティを活用して API リクエストデータを効率的に検証する方法を紹介しました。
Zod との組み合わせにより、クエリパラメータ、パスパラメータ、リクエストボディの各バリデーションをシンプルかつ一貫した実装が可能となります。
より詳細な情報や最新のアップデートについては、以下の公式ドキュメントをご覧ください。
Discussion