custom-format-validators
Compare original and translation side by side
🇺🇸
Original
English🇨🇳
Translation
ChineseCustom Format Validators in z-schema
z-schema中的自定义格式验证器
JSON Schema constrains string (or other) values beyond basic type checking. z-schema includes built-in validators and supports registering custom ones — both sync and async.
formatJSON Schema的关键字在基础类型检查之外,对字符串(或其他类型)的值进行约束。z-schema包含内置验证器,同时支持注册自定义验证器——包括同步和异步两种类型。
formatBuilt-in formats
内置格式
z-schema ships with validators for all standard JSON Schema formats:
| Format | Validates |
|---|---|
| RFC 3339 full-date ( |
| RFC 3339 date-time ( |
| RFC 3339 time ( |
| RFC 5321 email address |
| Internationalized email |
| RFC 1123 hostname |
| Internationalized hostname |
| IPv4 address |
| IPv6 address |
| RFC 3986 URI |
| URI or relative reference |
| RFC 6570 URI template |
| Internationalized URI |
| Internationalized URI reference |
| RFC 6901 JSON Pointer |
| Relative JSON Pointer |
| ECMA-262 regex |
| ISO 8601 duration |
| RFC 4122 UUID |
z-schema内置了所有标准JSON Schema格式的验证器:
| 格式名称 | 验证规则 |
|---|---|
| RFC 3339标准的完整日期(如 |
| RFC 3339标准的日期时间(如 |
| RFC 3339标准的时间(如 |
| RFC 5321标准的邮箱地址 |
| 国际化邮箱地址 |
| RFC 1123标准的主机名 |
| 国际化主机名 |
| IPv4地址 |
| IPv6地址 |
| RFC 3986标准的URI |
| URI或相对引用 |
| RFC 6570标准的URI模板 |
| 国际化URI |
| 国际化URI引用 |
| RFC 6901标准的JSON指针 |
| 相对JSON指针 |
| ECMA-262标准的正则表达式 |
| ISO 8601标准的时长格式 |
| RFC 4122标准的UUID |
Registering a sync format
注册同步格式验证器
A format validator is a function . Return if valid, if invalid. Return for non-applicable types (e.g., when input is not a string) — z-schema calls format validators for any value type.
(input: unknown) => booleantruefalsetrue格式验证器是一个类型的函数。验证通过返回,不通过返回。对于不适用的类型(如输入不是字符串)也应返回——z-schema会为任意类型的值调用格式验证器。
(input: unknown) => booleantruefalsetrueGlobal registration (shared across all instances)
全局注册(所有实例共享)
typescript
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);
});typescript
import ZSchema from 'z-schema';
ZSchema.registerFormat('postal-code', (value) => {
if (typeof value !== 'string') return true; // 跳过非字符串类型
return /^\d{5}(-\d{4})?$/.test(value);
});Instance-scoped registration
实例级注册
typescript
const validator = ZSchema.create();
validator.registerFormat('postal-code', (value) => {
if (typeof value !== 'string') return true;
return /^\d{5}(-\d{4})?$/.test(value);
});Instance formats override global formats with the same name.
typescript
const validator = ZSchema.create();
validator.registerFormat('postal-code', (value) => {
if (typeof value !== 'string') return true;
return /^\d{5}(-\d{4})?$/.test(value);
});实例级注册的格式会覆盖同名的全局注册格式。
Via options at creation time
创建实例时通过选项注册
typescript
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
},
});Pass to disable a built-in or globally registered format.
nulltypescript
const validator = ZSchema.create({
customFormats: {
'postal-code': (value) => typeof value === 'string' && /^\d{5}(-\d{4})?$/.test(value),
'always-valid': () => true,
'disable-email': null, // 禁用内置的邮箱验证器
},
});传入可以禁用内置或全局注册的格式验证器。
nullRegistering an async format
注册异步格式验证器
Return . The validator must be created with .
Promise<boolean>{ async: true }typescript
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);
}返回类型的结果。验证器必须通过选项创建。
Promise<boolean>{ async: true }typescript
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;
});
// 验证(返回Promise)
try {
await validator.validate(data, schema);
} catch (err) {
console.log(err.details);
}Timeout
超时设置
Async format validators time out after milliseconds (default: 2000). Increase for slow operations:
asyncTimeouttypescript
const validator = ZSchema.create({
async: true,
asyncTimeout: 10000, // 10 seconds
});Timed-out validators produce an error.
ASYNC_TIMEOUT异步格式验证器的默认超时时间为毫秒(默认2000)。对于慢操作可以增加超时时间:
asyncTimeouttypescript
const validator = ZSchema.create({
async: true,
asyncTimeout: 10000, // 10秒
});超时的验证器会抛出错误。
ASYNC_TIMEOUTFormat assertion behavior across drafts
不同JSON Schema版本中的格式断言行为
The JSON Schema spec changed how works in newer drafts:
format| Draft | Default behavior | With |
|---|---|---|
| draft-04/06/07 | Always asserts (fails on mismatch) | Always asserts |
| draft-2019-09 | Always asserts (z-schema default) | Annotation-only unless vocabulary enabled |
| draft-2020-12 | Always asserts (z-schema default) | Annotation-only unless vocabulary enabled |
z-schema defaults to (legacy — always assert). To respect the spec's vocabulary-aware behavior for modern drafts:
formatAssertions: nulltypescript
const validator = ZSchema.create({ formatAssertions: true });To disable all format assertions (annotation-only):
typescript
const validator = ZSchema.create({ formatAssertions: false });JSON Schema规范在新版本中修改了的工作方式:
format| 版本号 | 默认行为 | 开启 |
|---|---|---|
| draft-04/06/07 | 始终执行断言(不匹配则失败) | 始终执行断言 |
| draft-2019-09 | 始终执行断言(z-schema默认) | 仅作为注解,除非启用了对应的词汇表 |
| draft-2020-12 | 始终执行断言(z-schema默认) | 仅作为注解,除非启用了对应的词汇表 |
z-schema默认使用(兼容旧版——始终执行断言)。要让现代版本的验证器遵循规范中支持词汇表的行为,可配置:
formatAssertions: nulltypescript
const validator = ZSchema.create({ formatAssertions: true });要禁用所有格式断言(仅作为注解):
typescript
const validator = ZSchema.create({ formatAssertions: false });Unknown formats
未知格式处理
By default, z-schema reports for unrecognized format names in draft-04/06/07. Modern drafts (2019-09, 2020-12) always silently ignore unknown formats.
UNKNOWN_FORMATTo suppress unknown format errors in older drafts:
typescript
const validator = ZSchema.create({ ignoreUnknownFormats: true });默认情况下,在draft-04/06/07版本中,z-schema会为未识别的格式名称抛出错误。而在现代版本(2019-09、2020-12)中,会自动忽略未知格式。
UNKNOWN_FORMAT要在旧版本中抑制未知格式错误:
typescript
const validator = ZSchema.create({ ignoreUnknownFormats: true });Unregistering a format
注销格式验证器
typescript
// Global
ZSchema.unregisterFormat('postal-code');
// Instance
validator.unregisterFormat('postal-code');typescript
// 全局注销
ZSchema.unregisterFormat('postal-code');
// 实例级注销
validator.unregisterFormat('postal-code');Listing formats
列出格式验证器
typescript
// 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');typescript
// 列出全局注册的自定义格式
const customFormats = ZSchema.getRegisteredFormats();
// 列出实例支持的所有格式(内置+自定义)
const allFormats = validator.getSupportedFormats();
// 检查是否支持特定格式
const supported = validator.isFormatSupported('postal-code');Real-world patterns
实际应用场景
Phone number validation
电话号码验证
typescript
ZSchema.registerFormat('phone', (value) => {
if (typeof value !== 'string') return true;
return /^\+?[1-9]\d{1,14}$/.test(value); // E.164 format
});typescript
ZSchema.registerFormat('phone', (value) => {
if (typeof value !== 'string') return true;
return /^\+?[1-9]\d{1,14}$/.test(value); // E.164格式
});ISO 8601 date (strict)
严格ISO 8601日期验证
typescript
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];
});typescript
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];
});Business rule: value from external list
业务规则:验证外部列表中的值
typescript
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());
});typescript
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());
});Side-effect: prefill defaults
副作用:填充默认值
Format validators can mutate objects (use with caution):
typescript
ZSchema.registerFormat('fill-defaults', (obj) => {
if (typeof obj === 'object' && obj !== null) {
(obj as Record<string, unknown>).createdAt ??= new Date().toISOString();
}
return true;
});格式验证器可以修改对象(谨慎使用):
typescript
ZSchema.registerFormat('fill-defaults', (obj) => {
if (typeof obj === 'object' && obj !== null) {
(obj as Record<string, unknown>).createdAt ??= new Date().toISOString();
}
return true;
});Schema usage
Schema使用示例
json
{
"type": "object",
"properties": {
"phone": { "type": "string", "format": "phone" },
"country": { "type": "string", "format": "valid-country" },
"zipCode": { "type": "string", "format": "postal-code" }
}
}json
{
"type": "object",
"properties": {
"phone": { "type": "string", "format": "phone" },
"country": { "type": "string", "format": "valid-country" },
"zipCode": { "type": "string", "format": "postal-code" }
}
}