リクエストバリデーション 
リクエストバリデーションはKoriの型安全な開発体験の中核です。Koriの拡張可能なバリデーションシステムは、自動型生成を伴う型安全なランタイムバリデーションを提供します - キャストは不要です。Koriのアーキテクチャは異なるバリデーションライブラリをサポートするよう設計されていますが、公式にはファーストクラスのZod統合を提供し、Standard Schemaもサポートしています。
このガイドではZodを例として使用します。
セットアップ 
Zod統合パッケージをインストール:
npm install @korix/zod-schema-adapter zodバリデーション付きのKoriアプリケーションをセットアップ:
import { createKori } from '@korix/kori';
import {
  zodRequestSchema,
  enableZodRequestValidation,
} from '@korix/zod-schema-adapter';
import { z } from 'zod';
const app = createKori({
  ...enableZodRequestValidation(),
});基本例 
KoriがAPI開発をどのように変革するか、シンプルなリクエストボディバリデーションから始めて見てみましょう:
const UserSchema = z.object({
  name: z.string().min(1),
  age: z.number().int().min(0),
});
app.post('/users', {
  requestSchema: zodRequestSchema({
    body: UserSchema,
  }),
  handler: (ctx) => {
    // 完全に型付けされバリデーション済み!
    const user = ctx.req.validatedBody();
    return ctx.res.status(201).json({
      message: 'User created',
      user,
    });
  },
});Koriは自動的に処理します:
- リクエストボディの解析とバリデーション
 - スキーマからのTypeScript型推論
 - ハンドラーに到達する前の無効なリクエストの拒否
 
すべてのリクエスト部分のバリデーション 
Koriは、HTTPリクエストのすべての部分をバリデーションできます:パスパラメータ、クエリパラメータ、ヘッダー、リクエストボディ。
app.put('/users/:id', {
  requestSchema: zodRequestSchema({
    params: z.object({
      id: z.string().regex(/^\d+$/).transform(Number),
    }),
    queries: z.object({
      notify: z
        .enum(['true', 'false'])
        .transform((val) => val === 'true')
        .optional(),
      include: z.string().optional(),
    }),
    headers: z.object({
      authorization: z.string().startsWith('Bearer '),
    }),
    body: z.object({
      name: z.string().min(1).optional(),
      age: z.number().int().min(0).optional(),
    }),
  }),
  handler: (ctx) => {
    // すべてがバリデーション済みで適切に型付け
    const { id } = ctx.req.validatedParams();
    const { notify, include } = ctx.req.validatedQueries();
    const { authorization } = ctx.req.validatedHeaders();
    const updates = ctx.req.validatedBody();
    return ctx.res.json({
      userId: id,
      updates,
      willNotify: notify ?? false,
      token: authorization,
    });
  },
});リクエストボディのコンテンツタイプ 
デフォルトでは、KoriはJSONとフォームエンコードされたボディをサポートします。異なるコンテンツタイプのスキーマを明示的に定義できます:
const JsonUserSchema = z.object({
  name: z.string(),
  age: z.number().int().min(0),
});
const FormUserSchema = z.object({
  name: z.string(),
  // フォームデータの値は文字列なので、必要に応じて変換
  age: z.string().transform(Number),
});
app.post('/users', {
  requestSchema: zodRequestSchema({
    body: {
      content: {
        'application/json': JsonUserSchema,
        'application/x-www-form-urlencoded': FormUserSchema,
      },
    },
  }),
  handler: (ctx) => {
    const userData = ctx.req.validatedBody();
    // 判別可能なユニオンが型安全な処理を可能にする
    if (userData.mediaType === 'application/x-www-form-urlencoded') {
      // userData.valueはFormUser(number ageを持つ)として型付け
      const user = userData.value;
      return ctx.res.json({ source: 'form', user });
    } else {
      // userData.valueはJsonUser(オプションのageを持つ)として型付け
      const user = userData.value;
      return ctx.res.json({ source: 'json', user });
    }
  },
});エラーハンドリング 
Koriは複数のレベルのカスタマイゼーションでバリデーション失敗の柔軟なエラーハンドリングを提供します。
デフォルト動作 
デフォルトでは、バリデーション失敗は400 Bad Requestレスポンスを返します:
{
  "error": {
    "type": "BAD_REQUEST",
    "message": "Request validation failed"
  }
}コンテンツタイプエラーは、リクエストのコンテンツタイプが定義されたスキーマと一致しない場合に415 Unsupported Media Typeレスポンスを返します:
{
  "error": {
    "type": "UNSUPPORTED_MEDIA_TYPE",
    "message": "Unsupported Media Type"
  }
}カスタムエラーハンドラー 
ルートレベルとインスタンスレベルの両方でカスタムエラーハンドラーを提供して、バリデーションエラーレスポンスをカスタマイズできます。
ルートレベルエラーハンドラー 
特定のルートのバリデーションエラーを処理:
app.post('/users', {
  requestSchema: zodRequestSchema({
    body: UserCreateSchema,
  }),
  onRequestValidationFailure: (ctx, error) => {
    // 詳細なZodバリデーションエラーにアクセス
    if (
      error.body &&
      error.body.stage === 'validation' &&
      error.body.reason.type === 'Validation'
    ) {
      const zodError = error.body.reason;
      return ctx.res.badRequest({
        message: 'Validation failed',
        details: zodError.issues.map((issue) => ({
          field: issue.path.join('.'),
          message: issue.message,
          code: issue.code,
        })),
      });
    }
    return ctx.res.badRequest({
      message: 'Validation failed',
    });
  },
  handler: (ctx) => {
    const user = ctx.req.validatedBody();
    // ユーザー作成ロジック...
    return ctx.res.json({ message: 'User created', user });
  },
});インスタンスレベルエラーハンドラー 
すべてのルートに対するグローバルエラーハンドラーを設定:
const app = createKori({
  ...enableZodRequestValidation(),
  onRequestValidationFailure: (ctx, error) => {
    // グローバルバリデーションエラーハンドリング
    ctx.log().warn('Validation failed', { error });
    return ctx.res.status(400).json({
      error: 'Invalid request data',
      timestamp: new Date().toISOString(),
    });
  },
});ハンドラーの優先順位 
エラーハンドラーは以下の順序で呼ばれます:
- ルートレベルハンドラー(提供されている場合)
 - インスタンスレベルハンドラー(提供されている場合)
 - デフォルト動作
 
各ハンドラーは、レスポンスを返さずに次のハンドラーに渡すことでエラーを処理するか渡すかを選択できます。これにより、特定のハンドラーが特定のエラータイプのみを処理することが可能になります。