mcpField
V
validation

validation

github.com/profpowell開発644 回インストール4 週間前に更新
リポジトリ

validation について

AJVを使ってJavaScriptプロジェクトのJSON Schema検証を支援するスキルです。API入力やサービスデータを検証し、スキーマ、生成したTypeScript宣言、ドキュメントを連携させます。

主な機能

  1. 01AJVによるJSON Schema検証
  2. 02リクエスト本文・クエリ・パラメーター用ミドルウェア
  3. 03クエリパラメーターの型変換
  4. 04TypeScript宣言の生成
  5. 05スキーマとDB制約の整合

活用シーン

  1. 01APIリクエストやフォーム送信の検証
  2. 02データベース書き込み前のデータ確認
  3. 03サービス間の契約定義
  4. 04スキーマからTypeScript宣言を生成

インストール

コマンドをコピーしてターミナルで実行します。

$npx skills add https://github.com/profpowell/vanilla-breeze --skill validation

インストール後、Claude Code で/validationを入力して読み込まれたか確認します。

詳細

JSON Schema 検証スキル

AJV の実行時検証で JSON Schema 定義を使用し、すべての境界でデータを検証します。


使用する場面

  • ユーザー入力を受け付ける API エンドポイントを作成するとき
  • フォームの送信内容をサーバー側で検証するとき
  • データベースに書き込む前にデータの整合性を確保するとき
  • サービス間のコントラクトを定義するとき
  • スキーマから TypeScript 型を生成するとき

スキーマファイルの場所

スキーマは、次の構成の /schemas/ ディレクトリに配置します。

schemas/
  common/                    # Shared/reusable schemas
    uuid.schema.json
    error-response.schema.json
    pagination.schema.json
  entities/                  # Domain entity schemas
    user.schema.json         # Full entity
    user.create.schema.json  # Create input (no id/timestamps)
    user.update.schema.json  # Partial update (all optional)
  api/                       # API-specific request schemas
    login.schema.json
    register.schema.json

スキーマの命名規則

パターン例用途
{entity}.schema.jsonuser.schema.jsonすべてのフィールドを含む完全なエンティティ
{entity}.create.schema.jsonuser.create.schema.json作成時の入力(id とタイムスタンプを含まない)
{entity}.update.schema.jsonuser.update.schema.json部分更新(すべてのフィールドが任意)
{context}.schema.jsonlogin.schema.jsonコンテキスト固有のスキーマ

スキーマの作成

基本的なスキーマテンプレート
{
  "$schema": "https://json-schema.org/draft/2020-12/schema",
  "$id": "entities/user.create",
  "title": "Create User",
  "description": "Schema for creating a new user",
  "type": "object",
  "required": ["email", "password"],
  "properties": {
    "email": {
      "type": "string",
      "format": "email",
      "maxLength": 254,
      "description": "User's email address"
    },
    "password": {
      "type": "string",
      "minLength": 8,
      "maxLength": 128,
      "description": "User's password (8-128 characters)"
    },
    "name": {
      "type": "string",
      "minLength": 1,
      "maxLength": 100,
      "description": "User's display name"
    }
  },
  "additionalProperties": false
}
主な属性
属性用途
$id参照用の一意な識別子(例:"entities/user.create")
required必須フィールド名の配列
additionalProperties: false不明なフィールドを拒否します(セキュリティ)
minProperties: 1更新スキーマ向け。少なくとも 1 つのフィールドを必須にします
よく使われる検証キーワード

文字列の検証:

{
  "type": "string",
  "minLength": 1,
  "maxLength": 255,
  "pattern": "^[a-z0-9-]+$",
  "format": "email"
}

数値の検証:

{
  "type": "integer",
  "minimum": 1,
  "maximum": 100,
  "default": 20
}

列挙値の検証:

{
  "type": "string",
  "enum": ["draft", "active", "archived"],
  "default": "draft"
}

null を許容するフィールド:

{
  "type": ["string", "null"],
  "maxLength": 2000
}
利用可能なフォーマット

AJV は ajv-formats を使用して、次のフォーマットをサポートします。

  • email - メールアドレス
  • uri - 完全な URI
  • uuid - UUID v4
  • date - ISO 日付(YYYY-MM-DD)
  • date-time - ISO 日時
  • time - ISO 時刻
  • ipv4、ipv6 - IP アドレス
  • hostname - ホスト名

カスタムフォーマット(validator.js で定義):

  • phone - E.164 電話番号形式(+1234567890)
  • slug - URL で安全に使用できる識別子(小文字、ハイフン)

検証ミドルウェアの使用

インポートして適用する
import { validateBody, validateQuery, validateParams } from './middleware/validate.js';

// Validate request body
app.post('/api/users',
  validateBody('entities/user.create'),
  createUser
);

// Validate query parameters
app.get('/api/items',
  validateQuery('api/list-items'),
  listItems
);

// Validate path parameters
app.get('/api/users/:id',
  validateParams('common/uuid-param'),
  getUser
);

// Combined validation
app.patch('/api/users/:id',
  validateParams('common/uuid-param'),
  validateBody('entities/user.update'),
  updateUser
);
エラーレスポンス形式

検証に失敗した場合、次の内容を返します。

{
  "error": {
    "code": "VALIDATION_ERROR",
    "message": "Request validation failed",
    "details": [
      {
        "path": "/email",
        "message": "Invalid email format",
        "keyword": "format"
      },
      {
        "path": "/password",
        "message": "Must be at least 8 characters",
        "keyword": "minLength"
      }
    ]
  }
}

ステータスコード:

  • 422 - リクエストボディの検証に失敗しました
  • 400 - クエリまたはパラメーターの検証に失敗しました

サービスでの検証

ミドルウェア以外で検証する場合(例:データベースへの書き込み前)は、次のようにします。

import { validate } from '../api/middleware/validate.js';

async function createUser(data) {
  // Validate before database insert (defense in depth)
  validate(data, 'entities/user.create');

  // Proceed with insert...
  const result = await query(userQueries.create, [data.email, data.name]);
  return result.rows[0];
}

クエリパラメーターの型変換

クエリ文字列は常に文字列です。ミドルウェアは次の型変換を自動で行います。

スキーマの型入力結果
integer"20"20
boolean"true"true
array"a,b,c"["a", "b", "c"]

クエリスキーマの例:

{
  "$id": "api/list-items",
  "type": "object",
  "properties": {
    "limit": {
      "type": "integer",
      "minimum": 1,
      "maximum": 100,
      "default": 20
    },
    "offset": {
      "type": "integer",
      "minimum": 0,
      "default": 0
    },
    "status": {
      "type": "string",
      "enum": ["draft", "active", "archived"]
    }
  },
  "additionalProperties": false
}

TypeScript 型の生成

JSDoc の型チェック用に、スキーマから .d.ts ファイルを生成します。

npm run generate:types
仕組み

このスクリプトは json-schema-to-typescript を使用して、JSON Schema ファイルを TypeScript 宣言ファイルに変換します。

  1. /schemas/ 内のすべての .schema.json ファイルを読み込みます
  2. src/types/generated/ に対応する .d.ts ファイルを生成します
  3. 型は、型チェックのために JSDoc コメント内でインポートできます
生成される構成
src/types/generated/
  common/
    uuid.d.ts
    error-response.d.ts
    pagination.d.ts
  entities/
    user.d.ts
    user.create.d.ts
    user.update.d.ts
  api/
    login.d.ts
    register.d.ts
生成された型の使用

JSDoc コメント内で型をインポートします。

/**
 * @typedef {import('./types/generated/entities/user.create').UserCreate} CreateUserInput
 * @typedef {import('./types/generated/entities/user').User} User
 */

/**
 * Create a new user
 * @param {CreateUserInput} data - User creation data
 * @returns {Promise<User>} Created user
 */
async function createUser(data) {
  validate(data, 'entities/user.create');
  // data has full type information from schema
  const result = await db.query(userQueries.create, [data.email, data.password, data.name]);
  return result.rows[0];
}
型の再生成

スキーマを更新したときは、型を同期した状態に保つため npm run generate:types を実行してください。


データベース制約との整合

スキーマの検証内容は、データベースの制約に合わせる必要があります。

データベースの制約JSON Schema での指定
NOT NULLrequired 配列に含めます
UNIQUEサービス層で検証します(スキーマでは検証しません)
CHECK (status IN ('a', 'b'))"enum": ["a", "b"]
VARCHAR(255)"maxLength": 255
CHECK (amount > 0)"minimum": 1(排他的な場合は "exclusiveMinimum": 0)

OpenAPI との統合

OpenAPI 仕様からスキーマを参照します。

# openapi.yaml
paths:
  /users:
    post:
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: './schemas/entities/user.create.schema.json'
      responses:
        '201':
          content:
            application/json:
              schema:
                $ref: './schemas/entities/user.schema.json'
        '422':
          $ref: '#/components/responses/ValidationError'

tsc による型チェック

このプロジェクトでは、JSDoc アノテーション付きの JavaScript ファイルの型チェックに tsc --checkJs を使用します。

型チェックの実行
npm run typecheck
要件

型チェックには以下が必要です:

  1. @types パッケージをインストールするための npm install
  2. ファイルに JSDoc の型注釈が記述されていること
jsconfig.json の設定
{
  "compilerOptions": {
    "checkJs": true,
    "strict": true,
    "skipLibCheck": true,
    "target": "ES2022",
    "module": "NodeNext",
    "moduleResolution": "NodeNext"
  },
  "include": ["src/**/*.js", "test/**/*.js"],
  "exclude": ["node_modules"]
}
テンプレート構文の処理

テンプレート構文({{VARIABLE}})を含むファイルは、プロジェクトの作成時に処理されます。プロジェクトが生成されるまでは、型チェックの対象から除外してください。

スターターテンプレートの場合:

  • config/index.js のようなファイルには、{{PROJECT_NAME}} のプレースホルダーが含まれています
  • テンプレート処理後は、有効な JavaScript になります
  • 生成されたプロジェクトで npm install を実行した後は、型チェックが正しく実行されます
一般的な型のパターン
// Import Express types
/**
 * @typedef {import('express').Request} Request
 * @typedef {import('express').Response} Response
 * @typedef {import('express').NextFunction} NextFunction
 */

// Type middleware parameters
/**
 * @param {Request} req
 * @param {Response} res
 * @param {NextFunction} next
 */
export function myMiddleware(req, res, next) {
  // ...
}

// Import schema types (after npm run generate:types)
/**
 * @typedef {import('./types/generated/entities/user.create').UserCreate} CreateUserInput
 */

ベストプラクティス

  1. 信頼できる唯一の情報源 - スキーマでバリデーション、型、ドキュメントを定義します
  2. デフォルトで厳格に - 常に additionalProperties: false を使用します
  3. わかりやすいエラーメッセージ - すべてのプロパティで description を使用します
  4. 多層防御 - API の境界とデータベースへの書き込み前の両方でバリデーションを行います
  5. データベースとの整合性 - スキーマの制約を CHECK 制約と一致させます
  6. 重複せず生成する - TypeScript では npm run generate:types を使用します
  7. JSDoc の型を追加する - エクスポートするすべての関数に、引数と戻り値の型を記述します

関連スキル

  • rest-api - API エンドポイントのパターンと HTTP ステータスコード
  • error-handling - ValidationError を含むカスタムエラークラス
  • forms - クライアント側の HTML5 バリデーション(UX レイヤー)
  • security - 入力のサニタイズと出力のエンコード
  • typescript-author - TypeScript のパターンと Zod の代替手段

コメント