mcpField
V
validation

validation

github.com/profpowell开发644 次安装4 周前更新
代码仓库

关于 validation

面向 JavaScript 项目的 JSON Schema 验证技能,使用 AJV 指导开发者校验 API 输入和服务数据,并让 Schema、生成的 TypeScript 声明与文档保持一致。

主要功能

  1. 01基于 AJV 的 JSON Schema 验证
  2. 02请求体、查询和参数中间件
  3. 03查询参数类型转换
  4. 04生成 TypeScript 声明
  5. 05对齐 Schema 与数据库约束

适用场景

  1. 01校验 API 请求和表单提交
  2. 02写入数据库前检查数据
  3. 03定义服务间契约
  4. 04从 Schema 生成 TypeScript 声明

安装

复制下面的命令,在终端中运行。

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

安装后在 Claude Code 中输入/validation确认已加载。

详细介绍

JSON Schema 验证技能

使用 JSON Schema 定义和 AJV 运行时验证,在所有边界验证数据。


适用场景

  • 创建接受用户输入的 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用于更新架构——至少要求一个字段
常见验证关键字

字符串验证:

{
  "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"
}

可空字段:

{
  "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 类型

根据架构生成 .d.ts 文件,用于 JSDoc 类型检查:

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 NULL在 required 数组中列出
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 进行类型检查

项目使用 tsc --checkJs 对带有 JSDoc 注释的 JavaScript 文件进行类型检查。

运行类型检查
npm run typecheck
要求

类型检查需要:

  1. 运行 npm install 安装 @types 包
  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. 单一事实来源 - Schema 定义验证、类型和文档
  2. 默认严格 - 始终使用 additionalProperties: false
  3. 提供描述性错误消息 - 为每个属性使用 description
  4. 纵深防御 - 在 API 边界和写入数据库前都进行验证
  5. 与数据库保持一致 - Schema 约束应与 CHECK 约束匹配
  6. 生成而非重复 - 使用 npm run generate:types 生成 TypeScript
  7. 添加 JSDoc 类型 - 所有导出的函数都应标注参数和返回值类型

相关技能

  • rest-api - API 端点模式和 HTTP 状态码
  • error-handling - 自定义错误类,包括 ValidationError
  • forms - 客户端 HTML5 验证(UX 层)
  • security - 输入清理和输出编码
  • typescript-author - TypeScript 模式和 Zod 替代方案

评论

支持 Markdown