首页 > 解决方案 > 你如何使 json $ref 到本地文件?

问题描述

我在我的 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"
}

有人看到我的路径有什么问题吗?我知道您还应该使用#来选择要匹配的特定属性,但我希望使用 ENTIRE 模式。

标签: javascriptjsonschemaajv

解决方案


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

看看ajv.js.org 怎么说:

$ref 被解析为使用模式 $id 作为基本 URI 的 uri-reference(参见示例)。

和:

您不必在用作架构 $id 的 URI 上托管架构文件。这些 URI 仅用于识别模式,根据 JSON 模式规范,验证器不应期望能够从这些 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>


推荐阅读