如何将 json $ref 制作为本地文件?

Ros*_*sey 2 javascript jsonschema ajv

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

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

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

Run Code Online (Sandbox Code Playgroud)

我试图获得一个超级简单的$ref属性工作示例,但我遇到了麻烦。parent_schema.json好像:

{
  "properties": {
    "foo": { "type": "string" },
    "bar": { "$ref": "sub_schema.json" }
  }
}
Run Code Online (Sandbox Code Playgroud)

看起来sub_schema.json像:

{
  "properties": {
    "sub1": { "type": "string" },
  }
}
Run Code Online (Sandbox Code Playgroud)

data.json为了完整起见,我正在尝试验证我的内容:

{
  "foo": "whatever",
  "bar": {
    "sub1": "sometext"
  }
}
Run Code Online (Sandbox Code Playgroud)

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

MissingRefError {
    message: "can't resolve reference subschema1.json from id #"
    missingRef: "subschema1.json"
    missingSchema: "subschema1.json"
}
Run Code Online (Sandbox Code Playgroud)

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

cus*_*der 9

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

\n\n

看看ajv.js.org怎么说:

\n\n
\n

$ref 使用模式 $id 作为基本 URI 解析为 uri 引用(请参阅示例)。

\n
\n\n

和:

\n\n
\n

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

\n
\n\n

Ajv 不会尝试从stack://over.flow/string以下位置加载此架构:

\n\n
{\n  "$id": "stack://over.flow/string",\n  "type": "string"\n}\n
Run Code Online (Sandbox Code Playgroud)\n\n

如果您想在另一个模式中引用该模式,它们都需要具有相同的基本 URI,stack://over.flow/例如,

\n\n
{\n  "$id":  "stack://over.flow/object",\n  "type": "object",\n  "properties": {\n    "a": { "$ref": "string#" }\n  }\n}\n
Run Code Online (Sandbox Code Playgroud)\n\n

这里{ "$ref": "string#" }“在 stack://over.flow/string 导入架构”,所以你最终会得到:

\n\n
{\n  "$id":  "stack://over.flow/object",\n  "type": "object",\n  "properties": {\n    "a": {\n      "$id": "stack://over.flow/string",\n      "type": "string"\n    }\n  }\n}\n
Run Code Online (Sandbox Code Playgroud)\n\n

这允许您组合小模式:

\n\n

\r\n
\r\n
{\n  "$id": "stack://over.flow/string",\n  "type": "string"\n}\n
Run Code Online (Sandbox Code Playgroud)\r\n
{\n  "$id":  "stack://over.flow/object",\n  "type": "object",\n  "properties": {\n    "a": { "$ref": "string#" }\n  }\n}\n
Run Code Online (Sandbox Code Playgroud)\r\n
\r\n
\r\n

\n\n


\n\n

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

\n\n

回答你的问题:

\n\n

\r\n
\r\n
{\n  "$id":  "stack://over.flow/object",\n  "type": "object",\n  "properties": {\n    "a": {\n      "$id": "stack://over.flow/string",\n      "type": "string"\n    }\n  }\n}\n
Run Code Online (Sandbox Code Playgroud)\r\n
const ajv = new Ajv;\r\n\r\najv.addSchema({\r\n  "$id": "stack://over.flow/string",\r\n  "type": "string"\r\n});\r\n\r\najv.addSchema({\r\n  "$id": "stack://over.flow/number",\r\n  "type": "number"\r\n});\r\n\r\nconst is_string = ajv.getSchema("stack://over.flow/string");\r\nconst is_number = ajv.getSchema("stack://over.flow/number");\r\n\r\nconsole.log(is_string(\'aaa\'), is_string(42));\r\nconsole.log(is_number(\'aaa\'), is_number(42));\r\n\r\nconst is_ab = ajv.compile({\r\n  "$id":  "stack://over.flow/object",\r\n  "type": "object",\r\n  "properties": {\r\n    "a": { "$ref": "string#" },\r\n    "b": { "$ref": "number#" }\r\n  }\r\n});\r\n\r\nconsole.log(is_ab({a: "aaa", b: 42}));\r\nconsole.log(is_ab({a: 42, b: "aaa"}));
Run Code Online (Sandbox Code Playgroud)\r\n
\r\n
\r\n

\n

  • 从技术上讲,即使没有“type”关键字,OP 给出的示例也是有效的。这仅允许非对象(例如“null”、“string”、“number”)对这些模式有效(这可能是也可能不是所需的)。对于非对象,“properties”关键字将被忽略。话虽这么说,我相信某些验证器会按照您所描述的方式行事,并强制指定指定的“类型”,即,包含它可能是一种很好的做法,除非确实想要允许非对象值。 (2认同)