🧩

Nitroで、APIリクエストのデータをバリデーションする

2025/02/12に公開

こんにちは、合同会社Stegの keigo です。

本記事では、Nitro における API エンドポイントのバリデーション処理を、h3 が提供するバリデーションユーティリティを用いて効率的に実装する方法を紹介します。

クエリパラメータやリクエストボディのバリデーションを自前で実装すると、コードの冗長化や保守性の低下、エラーハンドリングのばらつきといった課題が生じることがあります。

今回紹介する方法は、これらの課題を解消し、シンプルかつ一貫性のあるバリデーション処理を実現するものです。

Nitroがサポートしているバリデーションユーティリティーについて

Nitroでは、h3が提供する以下3つのバリデーションユーティリティーをサポートしています。

  • getValidatedQuery
  • getValidatedRouterParams
  • readValidatedBody

https://h3.unjs.io/examples/validate-data

バリデーションには、Zodやjoi、myzodなど、任意のバリデーションライブラリを使用します。

本記事では、Zodと組み合わせたAPIリクエストデータのバリデーションを紹介します。

1. クエリパラメータのバリデーション (getValidatedQuery)

バリデーション未実装の例

まずは、フロントエンドから次のような 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 に文字列が指定されると、以下のようなエラーレスポンスが生成されます。

2. パスパラメータのバリデーション (getValidatedRouterParams)

バリデーション未実装の例

次に、以下のパスパラメータを持つ 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 エラーが返却されるようになります。

3. リクエストボディのバリデーション (readValidatedBody)

バリデーション未実装の例

次に、フロントエンドから以下のような 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 との組み合わせにより、クエリパラメータ、パスパラメータ、リクエストボディの各バリデーションをシンプルかつ一貫した実装が可能となります。

より詳細な情報や最新のアップデートについては、以下の公式ドキュメントをご覧ください。

https://h3.unjs.io/examples/validate-data

Steg Inc.

Discussion