关于 custom-format-validators
面向开发者的 z-schema 技能,介绍如何配置内置及自定义 JSON Schema 格式验证器。内容涵盖同步与异步注册、不同草案的格式行为及验证器管理。
主要功能
- 01内置 JSON Schema 格式
- 02注册同步和异步格式
- 03全局及实例级格式
- 04配置各草案的格式断言
- 05列出和注销格式
适用场景
- 01验证应用专用字符串格式
- 02根据外部数据检查值
- 03禁用内置格式检查
- 04查看已注册的格式
安装
复制下面的命令,在终端中运行。
npx skills add https:/ / github.com/ zaggino/ z-schema --skill custom-format-validators安装后在 Claude Code 中输入/custom-format-validators确认已加载。
详细介绍
z-schema 中的自定义格式验证器
JSON Schema 的 format 除了基本类型检查外,还会约束字符串(或其他)值。z-schema 内置了验证器,并支持注册自定义验证器,包括同步和异步验证器。
内置格式
z-schema 为所有标准 JSON Schema 格式提供了验证器:
| 格式 | 验证内容 |
|---|---|
date | RFC 3339 完整日期(2024-01-15) |
date-time | RFC 3339 日期时间(2024-01-15T09:30:00Z) |
time | RFC 3339 时间(09:30:00Z) |
email | RFC 5321 电子邮件地址 |
idn-email | 国际化电子邮件 |
hostname | RFC 1123 主机名 |
host-name | hostname 的别名 |
idn-hostname | 国际化主机名 |
ipv4 | IPv4 地址 |
ipv6 | IPv6 地址 |
uri | RFC 3986 URI |
strict-uri | 经过严格验证的 RFC 3986 URI(也是 strictUris: true 时替换 uri 的格式) |
uri-reference | URI 或相对引用 |
uri-template | RFC 6570 URI 模板(完整 ABNF,Errata 6937) |
iri | 国际化 URI |
iri-reference | 国际化 URI 引用 |
json-pointer | RFC 6901 JSON Pointer |
relative-json-pointer | 相对 JSON Pointer |
regex | ECMA-262 正则表达式 |
duration | ISO 8601 时长 |
uuid | RFC 4122 UUID |
注册同步格式
格式验证器是一个函数 (input: unknown) => boolean。有效时返回 true,无效时返回 false。对于不适用的类型(例如,输入不是字符串),请返回 true——z-schema 会对任何值类型调用格式验证器。
全局注册(所有实例共享)
import ZSchema from 'z-schema';
ZSchema.registerFormat('postal-code', (value) => {
if (typeof value !== 'string') return true; // skip non-strings
return /^\d{5}(-\d{4})?$/.test(value);
});
实例级注册
const validator = ZSchema.create();
validator.registerFormat('postal-code', (value) => {
if (typeof value !== 'string') return true;
return /^\d{5}(-\d{4})?$/.test(value);
});
实例格式会覆盖同名的全局格式。
创建时通过选项注册
const validator = ZSchema.create({
customFormats: {
'postal-code': (value) => typeof value === 'string' && /^\d{5}(-\d{4})?$/.test(value),
'always-valid': () => true,
'disable-email': null, // disable the built-in email validator
},
});
传入 null 可禁用内置格式或全局注册的格式。
注册异步格式
返回 Promise<boolean>。验证器必须使用 { async: true } 创建。
const validator = ZSchema.create({ async: true });
validator.registerFormat('user-exists', async (value) => {
if (typeof value !== 'number') return true;
const user = await db.findUser(value);
return user != null;
});
// Validate (returns Promise)
try {
await validator.validate(data, schema);
} catch (err) {
console.log(err.details);
}
超时
异步格式验证器会在 asyncTimeout 毫秒后超时(默认值:2000)。对于耗时较长的操作,请增大此值:
const validator = ZSchema.create({
async: true,
asyncTimeout: 10000, // 10 seconds
});
验证器超时会产生 ASYNC_TIMEOUT 错误。
不同草案中的格式断言行为
JSON Schema 规范在较新草案中更改了 format 的工作方式:
| 草案 | 默认行为 | 启用 formatAssertions: true 时 |
|---|---|---|
| draft-04/06/07 | 始终断言(不匹配时失败) | 始终断言 |
| draft-2019-09 | 始终断言(z-schema 默认行为) | 仅注解,除非启用了词汇 |
| draft-2020-12 | 始终断言(z-schema 默认行为) | 仅注解,除非启用了词汇 |
z-schema 默认将 formatAssertions: null(旧版行为——始终断言)。若要遵循现代草案中与词汇相关的规范行为:
const validator = ZSchema.create({ formatAssertions: true });
若要禁用所有格式断言(仅注解):
const validator = ZSchema.create({ formatAssertions: false });
未知格式
默认情况下,z-schema 会针对 draft-04/06/07 中无法识别的格式名称报告 UNKNOWN_FORMAT。现代草案(2019-09、2020-12)则始终静默忽略未知格式。
若要在较旧的草案中抑制未知格式错误:
const validator = ZSchema.create({ ignoreUnknownFormats: true });
注销格式
// Global
ZSchema.unregisterFormat('postal-code');
// Instance
validator.unregisterFormat('postal-code');
列出格式
// List globally registered custom formats
const customFormats = ZSchema.getRegisteredFormats();
// List all supported formats (built-in + custom) on an instance
const allFormats = validator.getSupportedFormats();
// Check if a specific format is supported
const supported = validator.isFormatSupported('postal-code');
实际应用模式
电话号码验证
ZSchema.registerFormat('phone', (value) => {
if (typeof value !== 'string') return true;
return /^\+?[1-9]\d{1,14}$/.test(value); // E.164 format
});
ISO 8601 日期(严格)
ZSchema.registerFormat('iso-date', (value) => {
if (typeof value !== 'string') return true;
const d = new Date(value);
return !isNaN(d.getTime()) && value === d.toISOString().split('T')[0];
});
业务规则:值来自外部列表
const validator = ZSchema.create({ async: true });
validator.registerFormat('valid-country', async (value) => {
if (typeof value !== 'string') return true;
const countries = await fetchValidCountries();
return countries.includes(value.toUpperCase());
});
副作用:预填默认值
格式验证器可以修改对象(请谨慎使用):
ZSchema.registerFormat('fill-defaults', (obj) => {
if (typeof obj === 'object' && obj !== null) {
(obj as Record<string, unknown>).createdAt ??= new Date().toISOString();
}
return true;
});
Schema 用法
{
"type": "object",
"properties": {
"phone": { "type": "string", "format": "phone" },
"country": { "type": "string", "format": "valid-country" },
"zipCode": { "type": "string", "format": "postal-code" }
}
}