你如何使json $ ref到本地文件?

时间:2020-06-12 16:34:49

标签: javascript jsonschema ajv

我在我的node.js项目中使用AJV软件包。

我正在尝试根据几个模式文件验证一些数据。这两个架构文件都在同一目录中:

/dir
    |
    parent_schema.json
    |
    sub_schema.json
/data
    |
    data.json

我正在尝试获取$ref属性正常工作的超简单示例,但是遇到了麻烦。 parent_schema.json如下:

{
  "properties": {
    "foo": { "type": "string" },
    "bar": { "$ref": "sub_schema.json" }
  }
}

sub_schema.json如下:

{
  "properties": {
    "sub1": { "type": "string" },
  }
}

我正在尝试验证我的data.json,为了完整起见,它看起来像:

{
  "foo": "whatever",
  "bar": {
    "sub1": "sometext"
  }
}

我遇到的问题是我的$ref路径。我从AJV收到此错误:

MissingRefError {
    message: "can't resolve reference subschema1.json from id #"
    missingRef: "subschema1.json"
    missingSchema: "subschema1.json"
}

有人知道我的路线出了什么问题吗?我知道您也应该使用#来选择要匹配的特定属性,但是我希望使用整个模式。

1 个答案:

答案 0 :(得分:1)

常见的误解是$ref以某种方式“加载”文件。

看看ajv.js.org怎么说:

使用架构$ id作为基本URI将$ ref解析为uri引用(请参见示例)。

并且:

您不必将架构文件托管在用作架构$ id的URI上。这些URI仅用于标识模式,根据JSON Schema规范,验证器不应期望能够从这些URI下载模式。

例如,Ajv不会尝试从stack://over.flow/string加载此架构:

{
  "$id": "stack://over.flow/string",
  "type": "string"
}

如果您要在其他模式中引用该模式,则它们都必须具有相同的基本URI stack://over.flow/,例如

{
  "$id":  "stack://over.flow/object",
  "type": "object",
  "properties": {
    "a": { "$ref": "string#" }
  }
}

这里{ "$ref": "string#" }“在堆栈://over.flow/string处导入模式” ,所以您最终得到:

{
  "$id":  "stack://over.flow/object",
  "type": "object",
  "properties": {
    "a": {
      "$id": "stack://over.flow/string",
      "type": "string"
    }
  }
}

这允许您组合小型架构:

const ajv = new Ajv;

ajv.addSchema({
  "$id": "stack://over.flow/string",
  "type": "string"
});

ajv.addSchema({
  "$id": "stack://over.flow/number",
  "type": "number"
});

const is_string = ajv.getSchema("stack://over.flow/string");
const is_number = ajv.getSchema("stack://over.flow/number");

console.log(is_string('aaa'), is_string(42));
console.log(is_number('aaa'), is_number(42));

const is_ab = ajv.compile({
  "$id":  "stack://over.flow/object",
  "type": "object",
  "properties": {
    "a": { "$ref": "string#" },
    "b": { "$ref": "number#" }
  }
});

console.log(is_ab({a: "aaa", b: 42}));
console.log(is_ab({a: 42, b: "aaa"}));
<script src="https://cdnjs.cloudflare.com/ajax/libs/ajv/6.12.2/ajv.min.js"></script>


(请注意,在您的示例中,两个模式都不正确。在两个模式中都缺少{"type": "object"}。)

回答您的问题:

const ajv = new Ajv;

ajv.addSchema({
  "$id": "stack://over.flow/parent.schema",
  "type": "object",
  "properties": {
    "foo": { "type": "string" },
    "bar": { "$ref": "child.schema#" }
  }
});

ajv.addSchema({
  "$id": "stack://over.flow/child.schema",
  "type": "object",
  "properties": {
    "sub1": { "type": "string" },
  }
});

const is_parent = ajv.getSchema("stack://over.flow/parent.schema");
const is_child = ajv.getSchema("stack://over.flow/child.schema");

console.log(is_parent({
  "foo": "whatever",
  "bar": {
    "sub1": "sometext"
  }
}));
<script src="https://cdnjs.cloudflare.com/ajax/libs/ajv/6.12.2/ajv.min.js"></script>