与 ajv 一起使用的 json-schema 的正确用法是什么?

What is the correct use of json-schema used with ajv?

早上好, 当对同一 json 文件中定义的内容使用 $ref 时,我在将 ajv 与 json-schema 一起使用时遇到问题。我怀疑问题出在id的使用上,我会对此了解更多。

我的文件是:

definitions.json

{
    "$schema":"http://json-schema.org/draft-06/schema#",
    "definitions": {
        "person":{
            "$schema":"http://json-schema.org/draft-06/schema#",
            "$id": "http://asite.org/schemas/person.json",
            "type":"object",
            "properties": {
                "name":{"type":"string"},
                "surname":{"type":"string"},
                "email": {"type": "string", "format": "email"},
                "sex":{"$ref": "types.json#/definitions/gender"}},
            "required":["name", "surname", "sex", "email"]
        },
        "member":{
            "$schema":"http://json-schema.org/draft-06/schema#",
            "type": "object",
            "$id": "http://asite.org/schemas/member.json",
            "allOf":[
                {"$ref": "#/definitions/person"},
                {
                    "properties": {
                        "id":{"type":"integer"},
                        "role":{"$ref": "types.json#/properties/man_role"},
                        "is_expert":{"type":"boolean", "default":false},
                        "is_board":{"type":"boolean", "default": false}
                    }
                }
            ]
        }
    },
    "type":"object",
    "properties": {
        "person": {"$ref": "#/definitions/person"},
        "member": {"$ref": "#/definitions/member"}
    }
}

types.json

{
    "$schema":"http://json-schema.org/draft-06/schema#",
    "$id": "http://asite.org/schemas/types.json",
    "type": "object",
    "definitions": {
        "gender":{"enum": ["male", "female"]},
        "man_role":{"enum": ["admin", "supervisor", "clerk", "none"]}
    },
    "properties":{
        "gender":{"$ref": "#/definitions/gender"},
        "man_role": {"$ref": "#/definitions/man_role"}
    }
}

我查看了 问题,但我没有弄清楚如何更正我的示例。 我得到的错误是:

MissingRefError: can't resolve reference #/definitions/person from id http://asite.org/schemas/member.json

如果我尝试使用 VisualStudio 代码,引用会起作用,例如我可以创建一个“成员”,它也可以识别“人”的属性。

谁能告诉我应该如何编写这些模式才能使它们与 ajv 一起工作?

产生错误的代码是:

import Ajv, {JSONSchemaType, DefinedError} from "ajv"
import {Person, Member} from "./definitions";
import addFormats from "ajv-formats"

const ajv = new Ajv();
addFormats(ajv);
ajv.addMetaSchema(require("../node_modules/ajv/lib/refs/json-schema-draft-06.json"))

const types = require("../types.json");
const PersonSchema : JSONSchemaType<Person> = require('../definitions.json').definitions.person;
const MemberSchema: JSONSchemaType<Member> = require('../definitions.json').definitions.member;
ajv.addSchema(types);

const isPerson = ajv.compile(PersonSchema);
const isMember = ajv.compile(MemberSchema)
//other stuff, use of isPerson and isMember on example objects

您的直觉是正确的,由于 $id$ref 未按您预期的方式解析。 $ref 是根据架构的 $id 解析的。在这种情况下,{ "$ref": "#/definitions/person" } 针对 "$id": "http://asite.org/schemas/member.json" 进行解析,导致 http://asite.org/schemas/member.json#/definitions/person 不存在。解决方案是使用 person 模式的 $id 而不是相对路径:{ "$ref": "person.json" }.


顺便说一句,您可能更喜欢替代 API 来编译模式,在处理像“definitions.json”这样的捆绑模式时效果更好。您可以加载整个文件,然后通过 $id.

编译您想要的各个模式
const ajv = new Ajv();
ajv.addMetaSchema(draft06);
ajv.addSchema(definitions);
ajv.addSchema(types);
const isPerson = ajv.getSchema("http://asite.org/schemas/person.json");
const isMember = ajv.getSchema("http://asite.org/schemas/member.json");