前端小知识 | JSONSchema

995 阅读1分钟

小知识,大挑战!本文正在参与“程序员必备小知识”创作活动。

前端小知识 | JSONSchema

JSON Schema

json-schema.org

  • 定义 JSON 数据和规范

  • 校验数据工具 Ajv.js

如何定义 Schema

yarn add ajv
// schema-tests/test1.js
// eslint-disable-next-line @typescript-eslint/no-var-requires
const Ajv = require('ajv') //
const ajv = new Ajv()

// 校验规则
const schema = {
  type: 'string', // 必须是字符串
  minLength: 10, // 最小 10 位
}

const validate = ajv.compile(schema)
const valid = validate('damowang')
if (!valid) console.log(validate.errors)
$ node ./schema-tests/test1.js
[
  {
    instancePath: '',
    schemaPath: '#/minLength',
    keyword: 'minLength',
    params: { limit: 10 },
    message: 'must NOT have fewer than 10 characters'
  }
]

定义对象校验规则

// eslint-disable-next-line @typescript-eslint/no-var-requires
const Ajv = require('ajv') //
const ajv = new Ajv()

const schema = {
  type: 'object',
  properties: {
    name: {
      type: 'string',
    },
    age: {
      type: 'number',
    },
    pets: {
      type: 'array',
      items: {
        type: 'string',
      },
    },
    isWorker: {
      type: 'boolean',
    },
  },
  required: ['name', 'age'], //哪些属性是必须输入的
}

const validate = ajv.compile(schema)
const valid = validate({
  name: 'damowang',
  age: 10,
  pets: [],
  isWorker: false,
})
if (!valid) console.log(validate, validate.errors)

自定义 Format

Format 只针对于 string 和 number

.addFormat(String , String|RegExp|Function|Object format) => Ajv

// eslint-disable-next-line @typescript-eslint/no-var-requires
const Ajv = require('ajv') //
const ajv = new Ajv()
// 自定义 Format
ajv.addFormat('test', (data) => {
  console.log(data, '--------')
  return data === 'hahaha'
})
const schema = {
  type: 'object',
  properties: {
    name: {
      type: 'string',
      format: 'test',
    },
    age: {
      type: 'number',
    },
    pets: {
      type: 'array',
      items: {
        type: 'string',
      },
    },
    isWorker: {
      type: 'boolean',
    },
  },
  required: ['name', 'age'], //哪些属性是必须输入的
}
const validate = ajv.compile(schema)

const valid = validate({
  name: 'damowang',
  age: 10,
  pets: [],
  isWorker: false,
})
if (!valid) console.log(validate, validate.errors)

如何在 AJV 中自定义关键字

方式 1 validate

// eslint-disable-next-line @typescript-eslint/no-var-requires
const Ajv = require('ajv') //
const ajv = new Ajv()

ajv.addFormat('test', (data) => {
  console.log(data, '--------')
  return data === 'hahaha'
})
ajv.addKeyword('testKeyword', {
  validate(schema, data) {
    console.log(schema, data)
    console.log(schema.length)
    if (schema === true) return true
    else return schema.length === 6
  },
})
const schema = {
  type: 'object',
  properties: {
    name: {
      type: 'string',
      // format: 'test',
      testKeyword: 'hahaha',
    },
    age: {
      type: 'number',
    },
    pets: {
      type: 'array',
      items: {
        type: 'string',
      },
    },
    isWorker: {
      type: 'boolean',
    },
  },
  required: ['name', 'age'], //哪些属性是必须输入的
}

const validate = ajv.compile(schema)

const valid = validate({
  name: 'hahaha',
  age: 10,
  pets: [],
  isWorker: false,
})
if (!valid) console.log(validate, validate.errors)

方式 2 compile

ajv.addKeyword('testKeyword', {
  compile(sch, parentSchema) {
    console.log(sch, parentSchema)
    return () => true
  },
})

方式 3 metaSchema

ajv.addKeyword('testKeyword', {
  compile(sch, parentSchema) {
    console.log(sch, parentSchema)
    return () => true
  },
  metaSchema: {
    type: 'string',
  },
})

方式 4 macro

ajv.addKeyword('testKeyword', {
  macro() {
    return {
      minLength: 10,
    }
  },
})

如何在 AJV 中如何转换错误信息语言

安装 ajv-i18n

yarn add ajv-i18n

配置代码

// eslint-disable-next-line @typescript-eslint/no-var-requires
const Ajv = require('ajv') //
const ajv = new Ajv()
// eslint-disable-next-line @typescript-eslint/no-var-requires
const localize = require('ajv-i18n')

ajv.addFormat('test', (data) => {
  console.log(data, '--------')
  return data === 'hahaha'
})

const schema = {
  type: 'object',
  properties: {
    name: {
      type: 'number',
    },
    age: {
      type: 'number',
    },
    pets: {
      type: 'array',
      items: {
        type: 'string',
      },
    },
    isWorker: {
      type: 'boolean',
    },
  },
  required: ['name', 'age'], //哪些属性是必须输入的
}

const validate = ajv.compile(schema)

const valid = validate({
  name: 'hahahahaaha',
  age: 10,
  pets: [],
  isWorker: false,
})
if (!valid) {
  // 返回中文错误信息
  localize.zh(validate.errors)
  console.log(validate, validate.errors)
}
$ node ./schema-tests/test1.js
[
	...
  {
    instancePath: '/name',
    schemaPath: '#/properties/name/type',
    keyword: 'type',
    params: { type: 'number' },
    message: '应当是 number 类型'
  }
]

如何在 JSONSchema 中定制校验错误信息

安装依赖

yarn add ajv-errors

代码示例

// eslint-disable-next-line @typescript-eslint/no-var-requires
const Ajv = require('ajv') //
const ajv = new Ajv({ allErrors: true, jsonPointers: true })

// eslint-disable-next-line @typescript-eslint/no-var-requires
require('ajv-errors')(ajv)

const schema = {
  type: 'object',
  properties: {
    name: {
      type: 'string',
      // test: false,
      errorMessage: {
        type: '必须是字符串',
        minLength: '长度不能小于 10',
      },
      minLength: 11,
    },
    age: {
      type: 'number',
    },
    pets: {
      type: 'array',
      items: {
        type: 'string',
      },
    },
    isWorker: {
      type: 'boolean',
    },
  },
  required: ['name', 'age'], //哪些属性是必须输入的
}

const validate = ajv.compile(schema)

const valid = validate({
  name: 'h',
  age: 10,
  pets: [],
  isWorker: false,
})
if (!valid) {
  console.log(validate.errors)
}