互联网工程任务组 | A. Wright,编 |
互联网草案 | |
预期状态:信息 | H. Andrews,编 |
过期时间:2017 年 10 月 23 日 | Cloudflare, Inc. |
2017 年 4 月 21 日 |
JSON 模式:用于描述 JSON 文档的媒体类型
draft-wright-json-schema-01
JSON 模式定义了媒体类型“application/schema+json”,这是一种基于 JSON 的格式,用于描述 JSON 数据的结构。JSON 模式断言 JSON 文档必须是什么样子,提取信息的方法,以及如何与之交互,非常适合为现有的 JSON API 添加注释,这些 API 否则不会有超媒体控制或可机器读取。
此草案的问题列表可以在 <https://github.com/json-schema-org/json-schema-spec/issues> 找到。
有关更多信息,请参见 <https://json-schema.fullstack.org.cn/>。
要提供反馈,请使用此问题跟踪器、主页上列出的通信方法,或向文档编辑人员发送电子邮件。
此互联网草案完全符合 BCP 78 和 BCP 79 的规定。
互联网草案是互联网工程任务组 (IETF) 的工作文档。请注意,其他团体也可能将工作文档作为互联网草案发布。当前互联网草案的列表在 http://datatracker.ietf.org/drafts/current/。
互联网草案是有效期最长为六个月的草案文档,可以随时更新、替换或被其他文档废弃。互联网草案不适合用作参考材料,也不适合引用,除非“正在进行中”。
此互联网草案将于 2017 年 10 月 23 日过期。
版权所有 (c) 2017 IETF 信托和被识别为文档作者的人员。保留所有权利。
本文件受 BCP 78 和 IETF 信托的《与 IETF 文档相关的法律条款》(http://trustee.ietf.org/license-info)约束,这些条款在本文件发布之日生效。请仔细阅读这些文件,因为它们描述了您对本文件的权利和限制。从本文件摘录的代码组件必须包含简化的 BSD 许可证文本,如信托法律条款第 4.e 节所述,并且按简化的 BSD 许可证中所述提供,不提供任何担保。
JSON 模式是一种 JSON 媒体类型,用于定义 JSON 数据的结构。JSON 模式旨在定义 JSON 数据的验证、文档、超链接导航和交互控制。
本规范定义了 JSON 模式核心术语和机制,包括通过引用指向另一个 JSON 模式、反引用 JSON 模式引用以及指定正在使用的词汇表。
其他规范定义了对验证、链接、注释、导航和交互进行断言的词汇表。
本文件中的关键词“必须”、“禁止”、“必需”、“应”、“不应”、“建议”、“不建议”、“推荐”、“可以”和“可选”应按 RFC 2119 [RFC2119] 中的描述进行解释。
本文件中的术语“JSON”、“JSON 文本”、“JSON 值”、“成员”、“元素”、“对象”、“数组”、“数字”、“字符串”、“布尔值”、“真”、“假”和“空”应按 RFC 7159 [RFC7159] 中的定义进行解释。
本文件提出了一种新的媒体类型“application/schema+json”,用于识别用于描述 JSON 数据的 JSON 模式。JSON 模式本身就是 JSON 文档。本规范及其相关规范定义了关键字,允许作者以多种方式描述 JSON 数据。
JSON 模式描述了 JSON 文档的结构(例如,必需属性和长度限制)。应用程序可以使用此信息来验证实例(检查是否满足约束),或告知接口收集用户输入以满足约束。
验证行为和关键字在 单独的文档 [json-schema-validation] 中指定。
JSON 超模式描述了 JSON 文档的超文本结构。这包括从实例到其他资源的链接关系、对实例作为多媒体数据的解释以及使用 API 所需的提交数据。
超模式行为和关键字在 单独的文档 [json-hyper-schema] 中指定。
JSON 文档是由 application/json 媒体类型描述的信息资源(一系列字节)。
在 JSON 模式中,术语“JSON 文档”、“JSON 文本”和“JSON 值”由于其定义的数据模型而可以互换。
JSON 模式仅针对 JSON 文档定义。但是,任何可以解析为 JSON 模式数据模型或根据 JSON 模式数据模型进行处理的文档或内存结构都可以针对 JSON 模式进行解释,包括 CBOR [RFC7049] 等媒体类型。
JSON 模式根据数据模型解释文档。根据此数据模型解释的 JSON 值称为“实例”。
实例具有六种基本类型之一,并且根据类型具有各种可能的值
因此,空格和格式问题超出了 JSON 模式的范围。
由于对象不能有两个具有相同键的属性,因此对于尝试在一个对象中定义两个具有相同键(“字符串”产生式)的属性(“成员”产生式)的 JSON 文档的行为是未定义的。
当且仅当两个 JSON 实例是相同类型并且根据数据模型具有相同的值时,它们被认为是相等的。具体而言,这意味着
此定义隐含了数组必须具有相同的长度、对象必须具有相同数量的成员、对象中的属性是无序的、没有定义多个具有相同键的属性的方法,并且仅仅的格式差异(缩进、逗号的位置、尾随零)无关紧要。
JSON 模式文档,或简称为模式,是一个 JSON 文档,用于描述实例。模式本身被解释为实例。JSON 模式必须是一个对象或一个布尔值。
布尔值等效于以下行为
用于描述实例的属性称为关键字或模式关键字。属性的含义由模式使用的词汇表指定。
JSON 模式可以包含不是模式关键字的属性。未知关键字应被忽略。
自身描述模式的模式称为元模式。元模式用于验证 JSON 模式并指定它使用的词汇表。
空模式是一个没有属性或只有未知属性的 JSON 模式。
根模式是构成所讨论的整个 JSON 文档的模式。
一些关键字本身采用模式,允许 JSON 模式嵌套
{ "title": "root", "items": { "title": "array item" } }
在本示例文档中,标题为“数组项目”的模式是一个子模式,标题为“根”的模式是根模式。
与根模式一样,子模式也是一个对象或一个布尔值。
根据 [RFC6839] 的第 3.1 节,为任何 +json 媒体类型指定的片段标识符的语法和语义应与为“application/json”指定的语法和语义相同。(在本文件发布时,尚未为“application/json”定义片段标识语法。)
此外,“application/schema+json”媒体类型支持两种片段标识符结构:普通名称和 JSON 指针。JSON 指针用作 URI 片段标识符的使用在 RFC 6901 [RFC6901] 中描述。与 JSON 指针语法匹配的片段标识符(包括空字符串)必须解释为 JSON 指针片段标识符。
根据 W3C 的 片段标识符最佳实践 [W3C.WD-fragid-best-practices-20121025],普通名称片段标识符保留用于引用本地命名的模式。所有与 JSON 指针语法不匹配的片段标识符必须解释为普通名称片段标识符。
在 "$id" 关键字 [id-keyword] 部分定义和引用普通名称片段标识符。
实例可以是 JSON [RFC7159] 中定义的任何有效 JSON 值。JSON 模式对类型没有任何限制:JSON 模式可以描述任何 JSON 值,包括例如 null。
JSON Schema 与编程语言无关,支持数据模型中描述的全部值范围。但是请注意,某些语言和 JSON 解析器可能无法在内存中表示 JSON 可描述的全部值范围。
一些编程语言和解析器使用不同的内部表示来表示浮点数和整数。
为了保持一致性,整数 JSON 数字不应以小数部分编码。
实现可以为 JSON Schema 定义额外的关键字。除了明确的协议之外,模式作者不应期望这些额外的关键字得到同行实现的支持。实现应该忽略它们不支持的关键字。
鼓励 JSON Schema 扩展的作者编写他们自己的元模式,这些模式使用 "allOf" 扩展现有的元模式。此扩展的元模式应使用 "$schema" 关键字引用,以允许工具遵循正确的行为。
"$schema" 关键字既用作 JSON Schema 版本标识符,也用作资源的位置,该资源本身是一个 JSON Schema,它描述了为该特定版本编写的任何模式。
此关键字的值必须是 URI [RFC3986](包含方案),并且此 URI 必须规范化。当前模式必须针对此 URI 标识的元模式有效。
"$schema" 关键字应在根模式中使用。它不能出现在子模式中。
[CREF1]虽然这种模式可能仍然是模式编写的最佳实践,但实现行为可能会在未来的草案中被修改或放宽。
此属性的值在其他文档和由其他方定义。JSON Schema 实现应根据合理的判断,实现对当前和以前发布的 JSON Schema 词汇表草案的支持。
"$ref" 关键字用于引用模式,并提供通过自引用验证递归结构的能力。
具有 "$ref" 属性的对象模式必须解释为 "$ref" 引用。"$ref" 属性的值必须是 URI 引用。相对于当前 URI 基准解析,它标识要使用的模式的 URI。"$ref" 对象中的所有其他属性必须被忽略。
URI 不是网络定位器,而只是一个标识符。如果它是可网络寻址的 URL,则模式不必从地址下载,并且实现不应假设它们应该在遇到可网络寻址的 URI 时执行网络操作。
模式不得针对模式陷入无限循环。例如,如果两个模式 "#alice" 和 "#bob" 都有一个 "allOf" 属性,该属性引用另一个属性,则一个简单的验证器可能会陷入无限递归循环中,试图验证实例。模式不应使用这种无限递归嵌套;行为未定义。
RFC3986 第 5.1 节 [RFC3986] 定义了如何确定文档的默认基准 URI。
信息性地,模式的初始基准 URI 是找到它的 URI,或者如果不知道的话,一个合适的替代 URI。
"$id" 关键字定义了模式的 URI,以及模式中其他 URI 引用解析的基准 URI。"$id" 关键字本身解析为对象整体出现的基准 URI。
如果存在,此关键字的值必须是字符串,并且必须表示有效的 URI 引用 [RFC3986]。此值应规范化,并且不应是空片段 <#> 或空字符串 <>。
JSON Schema 文档的根模式应包含一个带有 URI(包含方案)的 "$id" 关键字。此 URI 应不包含片段,或者包含一个空字符串。 [CREF2]包含具有其他组件的片段的 "$id" URI 引用应如何解释?有两种情况:当其他组件与当前基准 URI 匹配时,以及当它们更改基准 URI 时。
为了在 JSON Schema 文档中命名子模式,子模式可以使用 "$id" 为自己提供一个文档局部标识符。这是通过将 "$id" 设置为仅包含片段的 URI 引用来完成的。片段标识符必须以字母 ([A-Za-z]) 开头,后跟任意数量的字母、数字 ([0-9])、连字符 ("-")、下划线 ("_")、冒号 (":") 或句点 (".")。
定义一个既不符合上述要求也不属于有效 JSON 指针的 "$id" 的效果未定义。
{ "$id": "http://example.com/root.json", "definitions": { "A": { "$id": "#foo" }, "B": { "$id": "other.json", "definitions": { "X": { "$id": "#bar" }, "Y": { "$id": "t/inner.json" } } }, "C": { "$id": "urn:uuid:ee564b8a-7a87-4125-8c96-e9f123d6766f" } } }
例如
以下 URI 编码 JSON 指针 [RFC6901](相对于根模式)处的模式具有以下基准 URI,并且根据第 5 节可以由任一 URI 识别
模式可以通过任何赋予它们的 URI 来识别,包括 JSON 指针或它们由 "$id" 直接给出的 URI。
工具应注意模式(包括子模式)使用 "$id" 为自己提供的 URI。这被称为 "内部引用"。
例如,考虑此模式
{ "$id": "http://example.net/root.json", "items": { "type": "array", "items": { "$ref": "#item" } }, "definitions": { "single": { "$id": "#item", "type": "integer" } } }
当实现遇到 <#/definitions/single> 模式时,它将 "$id" URI 引用相对于当前基准 URI 解析,形成 <http://example.net/root.json#item>。
当实现随后查看 <#/items> 模式内部时,它会遇到 <#item> 引用,并将此解析为 <http://example.net/root.json#item>,它被理解为在同一文档中的其他位置定义的模式。
为了在一个庞大的生态系统中区分模式,模式通过 URI 来识别。如上所述,这并不一定意味着会下载任何内容,而是 JSON Schema 实现应该已经了解它们将使用的模式,包括识别它们的 URI。
实现应该能够将任意 URI 与任意模式关联起来,或者根据验证器对模式的信任程度自动关联模式的 "$id" 给出的 URI。
模式可以(并且很可能)具有多个 URI,但 URI 无法识别多个模式。当多个模式尝试使用相同的 URI 标识时,验证器应该引发错误条件。
JSON 已被 HTTP 服务器广泛用于自动化 API 和机器人。本节描述了在与支持媒体类型和 Web 链接 [RFC5988] 的协议一起使用时,如何以更 RESTful 的方式增强对 JSON 文档的处理。
建议由模式/配置文件描述的实例使用 "describedby" 链接关系提供指向可下载 JSON Schema 的链接,如 链接数据协议 1.0,第 8.1 节 [W3C.REC-ldp-20150226] 中定义的那样。
在 HTTP 中,此类链接可以使用 Link 标头 [RFC5988] 附加到任何响应。此类标头的示例将是
Link: <http://example.com/my-hyper-schema#>; rel="describedby"
实例可以指定 'profile' 链接关系 [RFC6906] 中描述的 "profile"。当用作媒体类型参数时,HTTP 服务器获得基于配置文件执行内容类型协商的能力。媒体类型参数必须是空格分隔的 URI 列表(即,相对引用无效)。
配置文件 URI 是不透明的,不应自动反引用。如果实现不了解提供的配置文件的语义,则实现可以改为遵循 "describedby" 链接(如果有),这些链接可能提供有关如何处理配置文件的信息。由于 "profile" 不一定指向网络位置,因此 "describedby" 关系用于链接到可下载的模式。但是,为了简便起见,模式作者应尽可能使这些 URI 指向同一个资源。
在 HTTP 中,媒体类型参数将在 Content-Type 标头内发送
Content-Type: application/json; profile="http://example.com/my-hyper-schema#"
多个配置文件用空格分隔
Content-Type: application/json; profile="http://example.com/alice http://example.com/bob"
HTTP 也可以在 Link 中发送 "profile",但如果这完全取代了媒体类型参数,可能会影响媒体类型语义和内容类型协商
Link: </alice>;rel="profile", </bob>;rel="profile"
当用于通过网络的超媒体系统时,HTTP [RFC7231] 通常是分发模式的首选协议。如果恶意客户端比必要时更频繁地通过网络提取模式,而实际上可以将模式缓存很长时间,则行为不端的客户端可能会给服务器维护者带来问题。
HTTP 服务器应在 JSON Schema 上设置长时间缓存的标头。HTTP 客户端应观察缓存标头,并且不应在它们的有效期内重新请求文档。分布式系统应利用共享缓存和/或缓存代理。
User-Agent: product-name/5.4.1 so-cool-json-schema/1.0.2 curl/7.43.0
客户端应设置或附加特定于 JSON Schema 实现或软件产品的 User-Agent 标头。由于符号按重要性降序排列,因此 JSON Schema 库名称/版本应位于更通用的 HTTP 库名称(如果有)之前。例如
客户端应该能够使用 "From" 标头发出请求,以便服务器操作员可以联系可能行为不端的脚本的所有者。
模式和实例都是 JSON 值。因此,RFC 7159 [RFC7159] 中定义的所有安全注意事项都适用。
实例和模式通常由不受信任的第三方编写,以部署在公共互联网服务器上。验证器应该注意,解析模式不会消耗过多的系统资源。验证器不得陷入无限循环。
服务器需要注意,恶意方不能通过上传具有预先存在的或非常相似的 "$id" 的模式来更改现有模式的功能。
各个 JSON Schema 词汇表也可能具有它们自己的安全注意事项。请参阅相应的规范以获取更多信息。
JSON Schema 的建议 MIME 媒体类型定义如下
[RFC2119] | Bradner, S.,"RFC 中用于指示要求级别的关键词",BCP 14,RFC 2119,DOI 10.17487/RFC2119,1997 年 3 月。 |
[RFC3986] | Berners-Lee, T.,Fielding, R. 和 L. Masinter,"统一资源标识符 (URI):通用语法",STD 66,RFC 3986,DOI 10.17487/RFC3986,2005 年 1 月。 |
[RFC6839] | Hansen, T. 和 A. Melnikov,"附加媒体类型结构化语法后缀",RFC 6839,DOI 10.17487/RFC6839,2013 年 1 月。 |
[RFC6901] | Bryan, P.,Zyp, K. 和 M. Nottingham,"JavaScript 对象符号 (JSON) 指针",RFC 6901,DOI 10.17487/RFC6901,2013 年 4 月。 |
[RFC7159] | Bray, T.,"JavaScript 对象符号 (JSON) 数据交换格式",RFC 7159,DOI 10.17487/RFC7159,2014 年 3 月。 |
[W3C.REC-ldp-20150226] | Speicher, S.,Arwe, J. 和 A. Malhotra,"链接数据平台 1.0",万维网联盟推荐 REC-ldp-20150226,2015 年 2 月。 |
[RFC5988] | Nottingham, M.,"网络链接",RFC 5988,DOI 10.17487/RFC5988,2010 年 10 月。 |
[RFC6906] | Wilde, E.,"'profile' 链接关系类型",RFC 6906,DOI 10.17487/RFC6906,2013 年 3 月。 |
[RFC7049] | Bormann, C. 和 P. Hoffman,"简洁二进制对象表示 (CBOR)",RFC 7049,DOI 10.17487/RFC7049,2013 年 10 月。 |
[RFC7231] | Fielding, R. 和 J. Reschke,"超文本传输协议 (HTTP/1.1):语义和内容",RFC 7231,DOI 10.17487/RFC7231,2014 年 6 月。 |
[W3C.WD-fragid-best-practices-20121025] | Tennison, J.,"片段标识符和媒体类型定义的最佳实践",万维网联盟 LastCall WD-fragid-best-practices-20121025,2012 年 10 月。 |
[json-schema-validation] | Wright, A. 和 G. Luff,"JSON 架构验证:JSON 结构验证词汇",互联网草案 draft-wright-json-schema-validation-00,2016 年 10 月。 |
[json-hyper-schema] | Wright, A. 和 G. Luff,"JSON 超级架构:JSON 超媒体注释词汇",互联网草案 draft-wright-json-schema-hyperschema-00,2016 年 10 月。 |
感谢 Gary Court、Francis Galiegue、Kris Zyp 和 Geraint Luff 对 JSON Schema 初稿的贡献。
感谢 Jason Desrosiers、Daniel Perrett、Erik Wilde、Ben Hutton、Evgeny Poberezkin、Brad Bowman、Gowry Sankar、Donald Pipowitch 和 Dave Finlay 对本文档的提交和补丁。