Метасхема — это схема, описывающая структуру и правила другой JSON Schema. Ajv использует метасхемы для:
Фактически метасхема отвечает на вопрос:
«Является ли данная схема корректной схемой?»
Пример обычной схемы:
const schema = {
type: "object",
properties: {
name: { type: "string" },
age: { type: "integer" }
},
required: ["name"]
}
Ajv способен проверить не только данные по этой схеме, но и саму схему на соответствие метасхеме JSON Schema Draft.
При создании экземпляра Ajv автоматически подключается метасхема определённого стандарта.
const Ajv = require("ajv")
const ajv = new Ajv()
По умолчанию Ajv проверяет схемы во время компиляции.
const validate = ajv.compile(schema)
Если схема содержит ошибку:
const schema = {
type: "unknownType"
}
Ajv выбросит исключение:
Error: schema is invalid
Причина — ключ type допускает только значения,
определённые метасхемой JSON Schema.
$schemaКлюч $schema определяет, какая метасхема должна
использоваться для проверки схемы.
Пример:
const schema = {
$schema: "https://json-schema.org/draft/2020-12/schema",
type: "string"
}
Ajv анализирует URI и выбирает соответствующую метасхему.
Ajv поддерживает несколько поколений стандарта JSON Schema.
Наиболее распространённая версия.
const Ajv = require("ajv")
const ajv = new Ajv()
Подключается отдельным классом.
const Ajv2019 = require("ajv/dist/2019")
const ajv = new Ajv2019()
Современная версия спецификации.
const Ajv2020 = require("ajv/dist/2020")
const ajv = new Ajv2020()
Метасхемы разных версий содержат различия в поддерживаемых ключевых словах.
{
additionalProperties: false
}
Появились:
unevaluatedPropertiesdependentSchemasdependentRequiredДобавлены:
prefixItems$dynamicRef$dynamicAnchorvalidateSchemaAjv предоставляет специальный метод для проверки схем.
const valid = ajv.validateSchema(schema)
console.log(valid)
Если схема некорректна:
console.log(ajv.errors)
Пример ошибки:
const schema = {
type: 123
}
Результат:
[
{
instancePath: "/type",
message: "must be equal to one of the allowed values"
}
]
Параметр validateSchema позволяет отключить
автоматическую проверку.
const ajv = new Ajv({
validateSchema: false
})
Используется редко, поскольку некорректная схема может привести к неправильной валидации данных.
Ajv позволяет подключать пользовательские метасхемы.
ajv.addMetaSchema(metaSchema)
Пример:
const metaSchema = {
$id: "https://example.com/custom-meta",
type: "object",
properties: {
type: {
enum: ["string", "number"]
}
}
}
Подключение:
ajv.addMetaSchema(metaSchema)
После этого схемы могут ссылаться на новую метасхему:
const schema = {
$schema: "https://example.com/custom-meta",
type: "string"
}
addSchema и addMetaSchemaaddSchemaДобавляет обычную схему данных.
ajv.addSchema(userSchema, "user")
addMetaSchemaДобавляет схему, описывающую другие схемы.
ajv.addMetaSchema(metaSchema)
$id в
метасхемахКаждая метасхема должна иметь уникальный идентификатор.
const metaSchema = {
$id: "https://example.com/meta",
type: "object"
}
Ajv использует $id:
$ref в метасхемахМетасхемы активно используют ссылки.
Пример:
const metaSchema = {
definitions: {
stringType: {
type: "string"
}
},
properties: {
name: {
$ref: "#/definitions/stringType"
}
}
}
Ajv разрешает ссылки во время компиляции схемы.
Метасхемы JSON Schema являются рекурсивными.
Пример:
{
properties: {
properties: {
additionalProperties: {
$ref: "#"
}
}
}
}
Здесь схема описывает другие схемы того же формата.
Метасхемы позволяют ограничивать структуру кастомных keyword.
ajv.addKeyword({
keyword: "positiveNumber",
type: "number",
validate(schema, data) {
return data > 0
},
metaSchema: {
type: "boolean"
}
})
metaSchema в keywordПоле metaSchema определяет допустимое значение самого
keyword.
В примере выше:
metaSchema: {
type: "boolean"
}
означает:
{
positiveNumber: true
}
разрешено, а:
{
positiveNumber: 123
}
вызовет ошибку схемы.
Форматы могут участвовать в проверке схем.
ajv.addFormat("only-a", {
type: "string",
validate: value => /^a+$/.test(value)
})
Метасхема JSON Schema определяет, что format должен быть
строкой.
Поэтому:
{
format: 123
}
является некорректной схемой.
strictStrict Mode усиливает проверку схем метасхемой.
const ajv = new Ajv({
strict: true
})
Ajv начинает:
Пример:
const schema = {
type: "string",
unknowKeyword: true
}
В strict mode:
Error: unknown keyword
const ajv = new Ajv({
strict: false
})
Ajv способен работать со схемами OpenAPI.
OpenAPI использует модифицированный вариант JSON Schema.
Для совместимости применяется опция:
const ajv = new Ajv({
discriminator: true
})
Некоторые инструменты добавляют собственные метасхемы OpenAPI.
Метасхема может разрешать использование асинхронных keyword.
ajv.addKeyword({
keyword: "idExists",
async: true,
type: "number",
validate: async (schema, data) => {
return true
}
})
При этом схема должна содержать:
{
$async: true
}
Корректность $async также проверяется метасхемой.
Ajv способен одновременно хранить несколько метасхем.
ajv.addMetaSchema(meta1)
ajv.addMetaSchema(meta2)
Выбор происходит через $schema.
{
$schema: "https://example.com/meta1"
}
Метасхему можно получить через getSchema.
const meta = ajv.getSchema(
"https://json-schema.org/draft/2020-12/schema"
)
ajv.removeSchema("https://example.com/meta")
Ajv удаляет схему из внутреннего реестра.
Метасхема JSON Schema сама является JSON Schema.
Фрагмент официальной метасхемы:
{
type: ["object", "boolean"],
properties: {
type: {
anyOf: [
{ $ref: "#/$defs/simpleTypes" },
{
type: "array",
items: {
$ref: "#/$defs/simpleTypes"
}
}
]
}
}
}
Здесь:
type;JSON Schema допускает использование boolean вместо объекта.
true
означает:
{}
false
означает:
{
not: {}
}
Метасхема обязана учитывать этот синтаксис.
Современные версии JSON Schema используют понятие dialect.
Диалект определяет:
Ajv ориентируется на URI метасхемы.
$defsВ новых версиях JSON Schema используется $defs.
{
$defs: {
positiveInt: {
type: "integer",
minimum: 1
}
}
}
Использование:
{
$ref: "#/$defs/positiveInt"
}
Метасхема определяет корректность структуры $defs.
Метасхемы позволяют ограничивать допустимые свойства схем.
Пример:
const metaSchema = {
type: "object",
properties: {
type: {
type: "string"
}
},
additionalProperties: false
}
Теперь схема:
{
type: "string",
unknown: true
}
станет некорректной.
Ajv компилирует метасхемы так же, как обычные схемы.
Это означает:
Проверка схемы метасхемой происходит:
compile;addSchema;addMetaSchema.Для больших проектов это может влиять на скорость запуска приложения.
Иногда применяют:
validateSchema: false
но только при полном контроле над схемами.
{
$schema: "http://json-schema.org/draft-04/schema#"
}
Ajv последних версий не поддерживает Draft-04 без дополнительных пакетов.
$idconst metaSchema = {
type: "object"
}
Без $id могут возникнуть проблемы со ссылками.
{
minimum: "10"
}
Метасхема требует число.
{
myKeyword: true
}
В strict mode схема станет невалидной.
const Ajv = require("ajv")
const ajv = new Ajv()
const metaSchema = {
$id: "https://example.com/app-meta",
type: "object",
properties: {
type: {
enum: ["string", "number", "boolean"]
},
description: {
type: "string"
}
},
required: ["type"],
additionalProperties: false
}
ajv.addMetaSchema(metaSchema)
const schema = {
$schema: "https://example.com/app-meta",
type: "string",
description: "User name"
}
console.log(
ajv.validateSchema(schema)
)
const invalidSchema = {
$schema: "https://example.com/app-meta",
type: "array"
}
Результат:
false
Ошибки:
console.log(ajv.errors)
[
{
instancePath: "/type",
message: "must be equal to one of the allowed values"
}
]
Метасхемы являются фундаментом экосистемы JSON Schema и Ajv.
Они обеспечивают: