validating-json-data

Compare original and translation side by side

🇺🇸

Original

English
🇨🇳

Translation

Chinese

Validating JSON Data with z-schema

使用z-schema验证JSON数据

z-schema validates JSON data against JSON Schema (draft-04, draft-06, draft-07, draft-2019-09, draft-2020-12). Default draft: draft-2020-12.
z-schema可根据JSON Schema(draft-04、draft-06、draft-07、draft-2019-09、draft-2020-12版本)验证JSON数据。默认版本为draft-2020-12

Quick start

快速开始

typescript
import ZSchema from 'z-schema';

const validator = ZSchema.create();

const schema = {
  type: 'object',
  properties: {
    name: { type: 'string' },
    age: { type: 'integer', minimum: 0 },
  },
  required: ['name'],
};

// Throws on invalid data
validator.validate({ name: 'Alice', age: 30 }, schema);
Install:
npm install z-schema
typescript
import ZSchema from 'z-schema';

const validator = ZSchema.create();

const schema = {
  type: 'object',
  properties: {
    name: { type: 'string' },
    age: { type: 'integer', minimum: 0 },
  },
  required: ['name'],
};

// 数据无效时抛出异常
validator.validate({ name: 'Alice', age: 30 }, schema);
安装命令:
npm install z-schema

Choosing a validation mode

选择验证模式

z-schema has four modes based on two toggles:
async
and
safe
. Pick the one that fits the use case.
ModeFactory callReturnsUse when
Sync throw
ZSchema.create()
true
or throws
ValidateError
Default — simple scripts and middleware
Sync safe
ZSchema.create({ safe: true })
{ valid, err? }
Need to inspect errors without try/catch
Async throw
ZSchema.create({ async: true })
Promise<true>
or rejects
Using async format validators
Async safe
ZSchema.create({ async: true, safe: true })
Promise<{ valid, err? }>
Async + non-throwing
z-schema基于
async
safe
两个开关提供四种模式,可根据使用场景选择合适的模式。
模式工厂调用方式返回值使用场景
同步抛出异常
ZSchema.create()
true
或抛出
ValidateError
默认模式——适用于简单脚本和中间件
同步安全模式
ZSchema.create({ safe: true })
{ valid, err? }
无需try/catch即可查看错误详情
异步抛出异常
ZSchema.create({ async: true })
Promise<true>
或拒绝Promise
使用异步格式验证器时需用此模式
异步安全模式
ZSchema.create({ async: true, safe: true })
Promise<{ valid, err? }>
异步场景且无需抛出异常

Sync throw (default)

同步抛出异常(默认)

typescript
import ZSchema from 'z-schema';

const validator = ZSchema.create();

try {
  validator.validate(data, schema);
} catch (err) {
  // err is ValidateError
  console.log(err.details); // SchemaErrorDetail[]
}
typescript
import ZSchema from 'z-schema';

const validator = ZSchema.create();

try {
  validator.validate(data, schema);
} catch (err) {
  // err 是 ValidateError 实例
  console.log(err.details); // SchemaErrorDetail[]
}

Sync safe

同步安全模式

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

const result = validator.validate(data, schema);
if (!result.valid) {
  console.log(result.err?.details);
}
Or call
.validateSafe()
on a regular (throwing) validator for the same result shape:
typescript
const validator = ZSchema.create();
const { valid, err } = validator.validateSafe(data, schema);
typescript
const validator = ZSchema.create({ safe: true });

const result = validator.validate(data, schema);
if (!result.valid) {
  console.log(result.err?.details);
}
也可在常规(抛出异常的)验证器上调用
.validateSafe()
方法,得到相同结构的返回结果:
typescript
const validator = ZSchema.create();
const { valid, err } = validator.validateSafe(data, schema);

Async throw

异步抛出异常

Required when using async format validators.
typescript
const validator = ZSchema.create({ async: true });

try {
  await validator.validate(data, schema);
} catch (err) {
  console.log(err.details);
}
使用异步格式验证器时必须使用此模式。
typescript
const validator = ZSchema.create({ async: true });

try {
  await validator.validate(data, schema);
} catch (err) {
  console.log(err.details);
}

Async safe

异步安全模式

typescript
const validator = ZSchema.create({ async: true, safe: true });

const { valid, err } = await validator.validate(data, schema);
typescript
const validator = ZSchema.create({ async: true, safe: true });

const { valid, err } = await validator.validate(data, schema);

Inspecting errors

查看错误详情

ValidateError
has
.details
— an array of
SchemaErrorDetail
:
typescript
interface SchemaErrorDetail {
  message: string; // "Expected type string but found type number"
  code: string; // "INVALID_TYPE"
  params: (string | number | Array<string | number>)[];
  path: string | Array<string | number>; // "#/age" or ["age"]
  keyword?: string; // "type", "required", "minLength", etc.
  inner?: SchemaErrorDetail[]; // sub-errors from anyOf/oneOf/not
  schemaPath?: Array<string | number>;
  schemaId?: string;
}
ValidateError
实例包含
.details
属性——一个
SchemaErrorDetail
数组:
typescript
interface SchemaErrorDetail {
  message: string; // "Expected type string but found type number"
  code: string; // "INVALID_TYPE"
  params: (string | number | Array<string | number>)[];
  path: string | Array<string | number>; // "#/age" 或 ["age"]
  keyword?: string; // "type", "required", "minLength" 等
  inner?: SchemaErrorDetail[]; // 来自anyOf/oneOf/not的子错误
  schemaPath?: Array<string | number>;
  schemaId?: string;
}

Example: walking nested errors

示例:遍历嵌套错误

Combinators (
anyOf
,
oneOf
,
not
) produce nested
inner
errors:
typescript
const { valid, err } = validator.validateSafe(data, schema);
if (!valid && err) {
  for (const detail of err.details) {
    console.log(`${detail.path}: [${detail.code}] ${detail.message}`);
    if (detail.inner) {
      for (const sub of detail.inner) {
        console.log(`  └─ ${sub.path}: [${sub.code}] ${sub.message}`);
      }
    }
  }
}
组合器(
anyOf
oneOf
not
)会产生嵌套的
inner
错误:
typescript
const { valid, err } = validator.validateSafe(data, schema);
if (!valid && err) {
  for (const detail of err.details) {
    console.log(`${detail.path}: [${detail.code}] ${detail.message}`);
    if (detail.inner) {
      for (const sub of detail.inner) {
        console.log(`  └─ ${sub.path}: [${sub.code}] ${sub.message}`);
      }
    }
  }
}

Filtering errors

过滤错误

Pass
ValidateOptions
as the third argument to include or exclude specific error codes:
typescript
// Only report type errors
validator.validate(data, schema, { includeErrors: ['INVALID_TYPE'] });

// Suppress string-length errors
validator.validate(data, schema, { excludeErrors: ['MIN_LENGTH', 'MAX_LENGTH'] });
For the full error code list, see references/error-codes.md.
ValidateOptions
作为第三个参数传入,可包含或排除特定错误代码:
typescript
// 仅报告类型错误
validator.validate(data, schema, { includeErrors: ['INVALID_TYPE'] });

// 屏蔽字符串长度相关错误
validator.validate(data, schema, { excludeErrors: ['MIN_LENGTH', 'MAX_LENGTH'] });
完整的错误代码列表请参考 references/error-codes.md

Schema pre-compilation

Schema预编译

Compile schemas at startup for better runtime performance and to resolve cross-references:
typescript
const validator = ZSchema.create();

const schemas = [
  {
    id: 'address',
    type: 'object',
    properties: { city: { type: 'string' }, zip: { type: 'string' } },
    required: ['city'],
  },
  {
    id: 'person',
    type: 'object',
    properties: {
      name: { type: 'string' },
      home: { $ref: 'address' },
    },
    required: ['name'],
  },
];

// Compile all schemas (validates them and registers references)
validator.validateSchema(schemas);

// Validate data using a compiled schema ID
validator.validate({ name: 'Alice', home: { city: 'Paris' } }, 'person');
在启动时编译Schema可提升运行时性能,并解析交叉引用:
typescript
const validator = ZSchema.create();

const schemas = [
  {
    id: 'address',
    type: 'object',
    properties: { city: { type: 'string' }, zip: { type: 'string' } },
    required: ['city'],
  },
  {
    id: 'person',
    type: 'object',
    properties: {
      name: { type: 'string' },
      home: { $ref: 'address' },
    },
    required: ['name'],
  },
];

// 编译所有Schema(验证Schema并注册引用)
validator.validateSchema(schemas);

// 使用已编译的Schema ID验证数据
validator.validate({ name: 'Alice', home: { city: 'Paris' } }, 'person');

Remote references

远程引用

Manual registration

手动注册

typescript
ZSchema.setRemoteReference('http://example.com/schemas/address.json', addressSchema);
// or per-instance:
validator.setRemoteReference('http://example.com/schemas/person.json', personSchema);
typescript
ZSchema.setRemoteReference('http://example.com/schemas/address.json', addressSchema);
// 或针对单个实例:
validator.setRemoteReference('http://example.com/schemas/person.json', personSchema);

Automatic loading via schema reader

通过Schema读取器自动加载

typescript
import fs from 'node:fs';
import path from 'node:path';

ZSchema.setSchemaReader((uri) => {
  const filePath = path.resolve(__dirname, 'schemas', uri + '.json');
  return JSON.parse(fs.readFileSync(filePath, 'utf8'));
});
typescript
import fs from 'node:fs';
import path from 'node:path';

ZSchema.setSchemaReader((uri) => {
  const filePath = path.resolve(__dirname, 'schemas', uri + '.json');
  return JSON.parse(fs.readFileSync(filePath, 'utf8'));
});

Diagnosing missing references

诊断缺失的引用

typescript
const { valid, err } = validator.validateSafe(data, schema);
if (!valid && err) {
  const missing = validator.getMissingReferences(err);
  const remote = validator.getMissingRemoteReferences(err);
}
typescript
const { valid, err } = validator.validateSafe(data, schema);
if (!valid && err) {
  const missing = validator.getMissingReferences(err);
  const remote = validator.getMissingRemoteReferences(err);
}

Custom format validators

自定义格式验证器

Global (shared across all validator instances)

全局(所有验证器实例共享)

typescript
ZSchema.registerFormat('postal-code', (value) => {
  return typeof value === 'string' && /^\d{5}(-\d{4})?$/.test(value);
});
typescript
ZSchema.registerFormat('postal-code', (value) => {
  return typeof value === 'string' && /^\d{5}(-\d{4})?$/.test(value);
});

Instance-scoped

实例作用域

typescript
const validator = ZSchema.create();
validator.registerFormat('postal-code', (value) => {
  return typeof value === 'string' && /^\d{5}(-\d{4})?$/.test(value);
});
typescript
const validator = ZSchema.create();
validator.registerFormat('postal-code', (value) => {
  return typeof value === 'string' && /^\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),
  },
});
typescript
const validator = ZSchema.create({
  customFormats: {
    'postal-code': (value) => typeof value === 'string' && /^\d{5}(-\d{4})?$/.test(value),
  },
});

Async format validators

异步格式验证器

Return
Promise<boolean>
. Requires
{ async: true }
.
typescript
const validator = ZSchema.create({ async: true });
validator.registerFormat('user-exists', async (value) => {
  if (typeof value !== 'number') return false;
  const user = await db.findUser(value);
  return user != null;
});
返回
Promise<boolean>
,需启用
{ async: true }
typescript
const validator = ZSchema.create({ async: true });
validator.registerFormat('user-exists', async (value) => {
  if (typeof value !== 'number') return false;
  const user = await db.findUser(value);
  return user != null;
});

Listing registered formats

列出已注册的格式

typescript
const formats = ZSchema.getRegisteredFormats();
typescript
const formats = ZSchema.getRegisteredFormats();

Choosing a draft version

选择draft版本

Set the draft explicitly if the schema targets a specific version:
typescript
const validator = ZSchema.create({ version: 'draft-07' });
Valid values:
'draft-04'
,
'draft-06'
,
'draft-07'
,
'draft2019-09'
,
'draft2020-12'
(default),
'none'
.
For a feature comparison across drafts, see references/draft-comparison.md.
如果Schema针对特定版本,可显式设置draft版本:
typescript
const validator = ZSchema.create({ version: 'draft-07' });
有效值:
'draft-04'
'draft-06'
'draft-07'
'draft2019-09'
'draft2020-12'
(默认)、
'none'
各draft版本的功能对比请参考 references/draft-comparison.md

Common options

常用选项

OptionDefaultPurpose
breakOnFirstError
false
Stop validation at the first error
noEmptyStrings
false
Reject empty strings as type
string
noEmptyArrays
false
Reject empty arrays as type
array
strictMode
false
Enable all strict checks at once
ignoreUnknownFormats
false
Suppress unknown format errors (modern drafts always ignore)
formatAssertions
null
null
=always assert,
true
=respect vocabulary,
false
=annotation-only
reportPathAsArray
false
Report error paths as arrays instead of JSON Pointer strings
For the full options reference, see references/options.md.
选项名称默认值用途
breakOnFirstError
false
遇到第一个错误时停止验证
noEmptyStrings
false
拒绝将空字符串视为
string
类型
noEmptyArrays
false
拒绝将空数组视为
array
类型
strictMode
false
一次性启用所有严格检查
ignoreUnknownFormats
false
屏蔽未知格式错误(现代draft版本默认忽略)
formatAssertions
null
null
=始终断言,
true
=遵循词汇表,
false
=仅作为注释使用
reportPathAsArray
false
以数组形式返回错误路径,而非JSON Pointer字符串
完整的选项参考请见 references/options.md

Validating sub-schemas

验证子Schema

Target a specific path within a schema:
typescript
validator.validate(carData, fullSchema, { schemaPath: 'definitions.car' });
针对Schema中的特定路径进行验证:
typescript
validator.validate(carData, fullSchema, { schemaPath: 'definitions.car' });

Browser usage (UMD)

浏览器使用(UMD)

html
<script src="node_modules/z-schema/umd/ZSchema.min.js"></script>
<script>
  var validator = ZSchema.create();
  try {
    validator.validate({ name: 'test' }, { type: 'object' });
  } catch (err) {
    console.log(err.details);
  }
</script>
html
<script src="node_modules/z-schema/umd/ZSchema.min.js"></script>
<script>
  var validator = ZSchema.create();
  try {
    validator.validate({ name: 'test' }, { type: 'object' });
  } catch (err) {
    console.log(err.details);
  }
</script>

TypeScript types

TypeScript类型

All types are exported from the package:
typescript
import type {
  JsonSchema, // Schema type (all drafts union)
  ZSchemaOptions, // Configuration options
  ValidateOptions, // Per-call options (schemaPath, includeErrors, excludeErrors)
  ValidateResponse, // { valid: boolean, err?: ValidateError }
  SchemaErrorDetail, // Individual error detail
  ErrorCode, // Error code string literal type
  FormatValidatorFn, // (input: unknown) => boolean | Promise<boolean>
  SchemaReader, // (uri: string) => JsonSchema
} from 'z-schema';

import { ValidateError } from 'z-schema';
所有类型均从包中导出:
typescript
import type {
  JsonSchema, // Schema类型(所有draft版本的联合类型)
  ZSchemaOptions, // 配置选项
  ValidateOptions, // 单次调用选项(schemaPath、includeErrors、excludeErrors)
  ValidateResponse, // { valid: boolean, err?: ValidateError }
  SchemaErrorDetail, // 单个错误详情
  ErrorCode, // 错误代码字符串字面量类型
  FormatValidatorFn, // (input: unknown) => boolean | Promise<boolean>
  SchemaReader, // (uri: string) => JsonSchema
} from 'z-schema';

import { ValidateError } from 'z-schema';

Reference files

参考文档

  • references/error-codes.md — Full error code list with descriptions and examples
  • references/options.md — Complete options reference with defaults
  • references/draft-comparison.md — Feature comparison across JSON Schema drafts
  • references/error-codes.md — 完整错误代码列表,含描述及示例
  • references/options.md — 完整选项参考,含默认值
  • references/draft-comparison.md — JSON Schema各draft版本的功能对比

Important conventions

重要约定

  • Always use
    ZSchema.create(options?)
    — never
    new ZSchema()
    . The factory returns the correctly typed variant.
  • Error details are on
    .details
    (not
    .errors
    ).
  • Import types with
    import type { ... }
    and values with
    import { ValidateError }
    .
  • Default draft is
    draft2020-12
    . Specify explicitly if targeting an older draft.
  • 始终使用
    ZSchema.create(options?)
    ——切勿使用
    new ZSchema()
    。工厂函数会返回类型正确的实例。
  • 错误详情在
    .details
    属性中(而非
    .errors
    )。
  • 使用
    import type { ... }
    导入类型,使用
    import { ValidateError }
    导入值。
  • 默认draft版本为
    draft2020-12
    。若针对旧版本draft,需显式指定。