mcpField
H
handling-validation-errors

handling-validation-errors

github.com/zaggino开发349171 次安装5 天前更新
代码仓库

关于 handling-validation-errors

面向使用 z-schema 处理验证错误的开发者。它说明如何捕获、检查、筛选和转换错误详情,以便在程序逻辑或表单界面中处理。

主要功能

  1. 01以抛错或安全模式捕获错误
  2. 02遍历嵌套错误详情
  3. 03将路径映射到表单字段
  4. 04按错误代码筛选
  5. 05自定义错误消息

适用场景

  1. 01在表单中显示模式错误
  2. 02处理嵌套的 anyOf 或 oneOf 错误
  3. 03仅展示选定的验证错误
  4. 04在首个错误处停止验证

安装

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

$npx skills add https://github.com/zaggino/z-schema --skill handling-validation-errors

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

详细介绍

处理 z-schema 中的验证错误

z-schema 会将验证错误报告为 ValidateError 对象,其中包含一个 SchemaErrorDetail 数组 .details。本技能介绍如何检查、筛选、映射和呈现这些错误。

错误结构

import { ValidateError } from 'z-schema';
import type { SchemaErrorDetail } from 'z-schema';

ValidateError 继承自 Error:

属性类型说明
.namestring始终为 'ValidateError'
.messagestring摘要消息
.detailsSchemaErrorDetail[]所有单条错误

每个 SchemaErrorDetail:

字段类型说明
messagestring面向用户的文本,例如 "Expected type string but found type number"
codestring机器可读的代码,例如 "INVALID_TYPE"
params(string | number | Array)[]用于填充消息模板占位符的值
pathstring | Array<string | number>出错值的 JSON Pointer("#/age" 或 ["age"])
keywordstring?导致错误的模式关键字("type"、"required" 等)
innerSchemaErrorDetail[]?组合器(anyOf、oneOf、not)产生的子错误
schemaPathArray<string | number>?模式中指向约束的路径
schemaIdstring?存在时的模式 ID
titlestring?存在时的模式 title
descriptionstring?存在时的模式 description

捕获错误

Try/catch(默认模式)
import ZSchema from 'z-schema';

const validator = ZSchema.create();

try {
  validator.validate(data, schema);
} catch (err) {
  if (err instanceof ValidateError) {
    for (const detail of err.details) {
      console.log(`[${detail.code}] ${detail.path}: ${detail.message}`);
    }
  }
}
安全模式(无需 try/catch)
const validator = ZSchema.create();
const { valid, err } = validator.validateSafe(data, schema);

if (!valid && err) {
  for (const detail of err.details) {
    console.log(`[${detail.code}] ${detail.path}: ${detail.message}`);
  }
}

遍历嵌套错误

组合器(anyOf、oneOf、not)会产生嵌套的 inner 错误。递归遍历器可处理任意深度:

function walkErrors(details: SchemaErrorDetail[], depth = 0): void {
  for (const detail of details) {
    const indent = '  '.repeat(depth);
    console.log(`${indent}[${detail.code}] ${detail.path}: ${detail.message}`);
    if (detail.inner) {
      walkErrors(detail.inner, depth + 1);
    }
  }
}

const { valid, err } = validator.validateSafe(data, schema);
if (!valid && err) {
  walkErrors(err.details);
}
收集所有叶级错误

展平树结构以获取每个具体错误,同时跳过组合器包装项:

function collectLeafErrors(details: SchemaErrorDetail[]): SchemaErrorDetail[] {
  const leaves: SchemaErrorDetail[] = [];
  for (const detail of details) {
    if (detail.inner && detail.inner.length > 0) {
      leaves.push(...collectLeafErrors(detail.inner));
    } else {
      leaves.push(detail);
    }
  }
  return leaves;
}

将错误映射到表单字段

将 JSON Pointer 路径转换为字段名称,用于 UI 表单验证:

function pathToFieldName(path: string | Array<string | number>): string {
  if (Array.isArray(path)) {
    return path.join('.');
  }
  // JSON Pointer string: "#/address/city" → "address.city"
  return path.replace(/^#\/?/, '').replace(/\//g, '.');
}

function errorsToFieldMap(details: SchemaErrorDetail[]): Record<string, string[]> {
  const map: Record<string, string[]> = {};
  const leaves = collectLeafErrors(details);
  for (const detail of leaves) {
    const field = pathToFieldName(detail.path) || '_root';
    (map[field] ??= []).push(detail.message);
  }
  return map;
}

// Usage
const { valid, err } = validator.validateSafe(formData, schema);
if (!valid && err) {
  const fieldErrors = errorsToFieldMap(err.details);
  // { "email": ["Expected type string but found type number"],
  //   "age": ["Value 150 is greater than maximum 120"] }
}
使用数组路径

启用 reportPathAsArray,以便更轻松地通过程序访问:

const validator = ZSchema.create({ reportPathAsArray: true });
const { valid, err } = validator.validateSafe(data, schema);
// err.details[0].path → ["address", "city"] instead of "#/address/city"

筛选错误

按调用筛选

将 includeErrors 或 excludeErrors 作为第三个参数传入:

// Only report type mismatches
validator.validate(data, schema, { includeErrors: ['INVALID_TYPE'] });

// Suppress string-length errors
validator.validate(data, schema, { excludeErrors: ['MIN_LENGTH', 'MAX_LENGTH'] });
以编程方式事后筛选
const { valid, err } = validator.validateSafe(data, schema);
if (!valid && err) {
  const typeErrors = err.details.filter((d) => d.code === 'INVALID_TYPE');
  const requiredErrors = err.details.filter((d) => d.code === 'OBJECT_MISSING_REQUIRED_PROPERTY');
}

自定义错误消息

将错误代码映射为便于用户理解的消息:

const friendlyMessages: Record<string, (detail: SchemaErrorDetail) => string> = {
  INVALID_TYPE: (d) => `${pathToFieldName(d.path)} must be a ${d.params[0]}`,
  OBJECT_MISSING_REQUIRED_PROPERTY: (d) => `${d.params[0]} is required`,
  MINIMUM: (d) => `${pathToFieldName(d.path)} must be at least ${d.params[1]}`,
  MAXIMUM: (d) => `${pathToFieldName(d.path)} must be at most ${d.params[1]}`,
  MIN_LENGTH: (d) => `${pathToFieldName(d.path)} must be at least ${d.params[1]} characters`,
  MAX_LENGTH: (d) => `${pathToFieldName(d.path)} must be at most ${d.params[1]} characters`,
  PATTERN: (d) => `${pathToFieldName(d.path)} has an invalid format`,
  ENUM_MISMATCH: (d) => `${pathToFieldName(d.path)} must be one of the allowed values`,
  INVALID_FORMAT: (d) => `${pathToFieldName(d.path)} is not a valid ${d.params[0]}`,
  ARRAY_UNEVALUATED_ITEMS: () => `Array contains items not covered by any schema`,
  OBJECT_UNEVALUATED_PROPERTIES: (d) => `${d.params[0]} is not allowed by the schema`,
  COLLECT_EVALUATED_DEPTH_EXCEEDED: (d) => `Schema nesting too deep (max ${d.params[0]})`,
  MAX_RECURSION_DEPTH_EXCEEDED: (d) => `Recursion depth exceeded (max ${d.params[0]})`,
};

function toFriendlyMessage(detail: SchemaErrorDetail): string {
  const fn = friendlyMessages[detail.code];
  return fn ? fn(detail) : detail.message;
}

在首个错误处停止

适用于快速失败场景:

const validator = ZSchema.create({ breakOnFirstError: true });

这只会报告遇到的第一个错误,从而减少迭代修复时的干扰。

使用 keyword 字段

keyword 字段会告知你是哪个模式关键字触发了错误,可用于通过程序对错误进行分类:

const { valid, err } = validator.validateSafe(data, schema);
if (!valid && err) {
  for (const detail of err.details) {
    switch (detail.keyword) {
      case 'required':
        // handle missing field
        break;
      case 'type':
        // handle type mismatch
        break;
      case 'format':
        // handle format failure
        break;
    }
  }
}

参考文件

如需查看完整错误代码列表及其说明,请参阅 validating-json-data 技能的 错误代码参考。

评论

支持 Markdown