互联网工程任务组 H. Andrews,编辑
互联网草案 Cloudflare, Inc.
预期状态:信息性 A. Wright,编辑
到期日期:2018 年 5 月 24 日 2017 年 11 月 20 日

JSON 超级模式:用于 JSON 超媒体注释的词汇
draft-handrews-json-schema-hyperschema-00

摘要

JSON 模式是一种基于 JSON 的格式,用于使用各种词汇描述 JSON 数据。本文件指定了一种用于使用超链接注释 JSON 文档的词汇。这些超链接包括描述如何通过 HTTP 等超媒体环境操作和交互远程资源的属性,以及根据实例值确定链接是否可用。本文件描述的超链接序列化格式也可以独立于 JSON 模式使用。

读者注意事项

此草案的问题列表可以在 <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/。

互联网草案是有效期最长为六个月的草案文档,可能随时更新、替换或被其他文档废止。不建议将互联网草案用作参考材料或引用,除非是作为“正在进行的工作”。

此互联网草案将于 2018 年 5 月 24 日到期。

版权声明

版权所有 (c) 2017 IETF 信托基金和被识别为文档作者的人员。保留所有权利。

本文件受 BCP 78 和 IETF 信托基金的 IETF 文档法律条款 (http://trustee.ietf.org/license-info) 约束,这些条款在发布本文件之日起生效。请仔细阅读这些文档,因为它们描述了您对本文件的权利和限制。从本文件摘录的代码组件必须包含简化的 BSD 许可证文本,如信托基金法律条款第 4.e 节所述,并且按简化的 BSD 许可证提供,不提供任何担保。


目录

1. 简介

JSON 超级模式是一个 JSON 模式词汇,用于使用超链接和指令注释 JSON 文档,以通过 HTTP 等超媒体环境处理和操作远程 JSON 资源。

术语 JSON 超级模式用于指代使用这些关键字的 JSON 模式。术语“超级模式”本身是指本规范范围内的 JSON 超级模式。

用于指定链接的主要机制是链接描述对象 (LDO),它是 RFC 8288 第 2 节 [RFC8288] 中定义的抽象链接模型的序列化。

本规范将使用 JSON 模式核心 [json-schema]JSON 模式验证 [json-schema-validation] 规范中定义的概念、语法和术语。建议读者拥有这些规范的副本。

2. 符号约定

本文件中的关键词“必须”、“禁止”、“必需”、“应该”、“不应该”、“建议”、“不建议”、“可选”和“可选”应按 RFC 2119 [RFC2119] 中的描述进行解释。

3. 概述

JSON 超级模式可以通过描述如何从实例数据构建超链接来构建来自 JSON 文档的超媒体系统。

JSON 实例文档和该实例的有效 application/schema+json 超级模式的组合充当单个超媒体表示。通过允许这种分离,基于超级模式的系统可以很好地支持期望纯 JSON 的应用程序,同时为支持超级模式的应用程序和用户代理提供完整的超媒体功能。

用户代理可以通过查找 application/schema+json 媒体类型和指示超级模式词汇存在的 "$schema" 值来检测超级模式的存在。用户代理可以使用 JSON 超级模式的实现将模式和实例文档的组合作为一个逻辑表示,作为一个资源的逻辑表示,就像任何单文档超媒体表示格式一样。

超级模式允许表示在网络上占用更少的字节,并将链接构建的负担从服务器分配到每个客户端。用户代理无需构建链接,除非客户端应用程序请求该链接。JSON 超级模式还可以在服务器端用于在运行时生成其他链接序列化或表示格式,或预先进行链接以促进服务器推送使用。

以下是一个示例超级模式,它添加了一个带有 IANA 注册的链接关系类型“self”的单个链接,该链接是根据实例构建的,该实例有一个名为“id”的已知对象字段

{
    "type": "object",
    "properties": {
        "id": {
            "type": "number",
            "readOnly": true
        }
    },
    "links": [
        {
            "rel": "self",
            "href": "thing/{id}"
        }
    ]
}
                

如果实例是 {"id": 1234},并且其根据 RFC 3986 第 5.1 节 [RFC3986] 的基本 URI 是“https://api.example.com/”,那么“https://api.example.com/thing/1234”就是生成的链接的目标 URI。

3.1. 术语

术语“模式”、“实例”和“元模式”应按 JSON 模式核心规范 [json-schema] 中定义的进行解释。

术语“适用”和“附加”应按 JSON 模式验证规范第 3 节 [json-schema-validation] 中定义的进行解释。

术语“链接”、“链接上下文”(或“上下文”)、“链接目标”(或“目标”)和“目标属性”应按 RFC 8288 第 2 节 [RFC8288] 中定义的进行解释。

术语“用户代理”应按 RFC 7230 第 2.1 节 [RFC7230] 中定义的进行解释,概括应用于任何可以在超媒体系统中使用的协议,而不是专门作为 HTTP 客户端。

本规范定义了以下术语

JSON 超级模式
使用本规范定义的关键字的 JSON 模式。
超级模式
在本文件中,术语“超级模式”始终指代 JSON 超级模式
链接有效性
对于实例的有效链接是适用于该实例的链接,并且不违反链接描述对象中的关键字施加的任何要求。
通用用户代理
可以用于与任何服务器的任何资源交互的用户代理,可以从其支持的标准化链接关系、媒体类型、URI 方案和协议中进行交互;虽然它可以扩展以专门处理特定媒体类型配置文件。
客户端应用程序
使用超媒体系统来完成特定目的的应用程序。这样的应用程序也可能成为它自己的用户代理,或者它也可能建立在通用用户代理之上。客户端应用程序使用其域特定的链接关系、媒体类型、URI 方案、协议和数据结构进行编程。
客户端输入
通过用户代理提供的,通常也通过客户端应用程序提供的,数据。此类数据可以从用户交互式地请求,或在交互之前以命令行参数、配置文件或源代码中的硬编码值等形式提供。
操作
超链接的特定用法,例如发出网络请求(对于具有诸如“http://”之类的方案的 URI,该方案指示协议)或基于链接采取其他操作(从“data:”URI 读取数据,或基于“mailto:”链接构造电子邮件)。对于支持多种方法的协议(如 HTTP),每种方法都被视为对同一链接的独立操作。

3.2. 功能

JSON 超级模式实现能够接收超级模式、实例,并在某些情况下接收客户端输入,并生成一组完全解析的有效链接。如 RFC 8288 第 2 节 [RFC8288] 所定义,链接由上下文、类型化关系、目标以及可选的附加目标属性组成。

关系类型和目标属性直接取自每个链接的链接描述对象。上下文和目标标识符由 URI 模板、实例数据以及(在目标标识符的情况下)客户端输入的某种组合构建。

目标始终由 URI 完全标识。由于缺乏用于 application/json 和许多其他可与 JSON 超级模式一起使用的媒体类型的 URI 片段标识符语法,上下文可能仅由 URI 部分标识。在这种情况下,其余标识将作为 JSON 指针提供。

JSON 超级模式文档中对几个 IANA 注册的链接关系类型赋予了特定的语义。“self”链接用于与实例文档所代表的资源交互,而“collection”和“item”链接标识了可以假定特定于集合的语义的资源。

4. 元模式和输出模式

[CREF1]“draft-07-wip” 是一个占位符。

JSON 超级模式元模式的当前 URI 为 <https://json-schema.fullstack.org.cn/draft-07/hyper-schema#>.

链接描述格式 [ldo] 可在没有 JSON Schema 的情况下使用,并且可以通过将规范性链接描述模式引用为使用这些链接的数据结构的模式来声明使用此格式。规范性链接描述模式的 URI 为:<https://json-schema.fullstack.org.cn/draft-07/links#>.

JSON 超级模式实现可以自由地以任何格式提供输出。但是,在一致性测试套件中使用了一种特定格式,该格式也用于说明 “实现要求” [implementation] 中的要点,以及显示由 示例 [examples] 生成的输出。建议实现能够以这种格式生成输出,以方便测试。描述推荐输出格式的 JSON Schema 的 URI 为 <https://json-schema.fullstack.org.cn/draft-07/hyper-schema-output#>.

5. 模式关键字

所有适用于实例中位置的模式的超级模式关键字(如 JSON Schema 验证的第 3 节 [json-schema-validation] 所定义)可与该实例一起使用。

当多个子模式适用于给定的子实例时,所有“link”数组 MUST 组合到一个集合中,以任何顺序。结果集中每个对象 MUST 保留其自己的适用“base”值的列表,这些值按解析顺序来自同一个模式和任何父模式。

与所有 JSON Schema 关键字一样,本节中描述的所有关键字都是可选的。最小的有效 JSON 超级模式是空对象。

5.1. base

如果存在,此关键字 MUST 首先 解析为 URI 模板 [uriTemplating],然后 MUST 作为 URI 引用针对实例的当前 URI 基准解析。结果 MUST 作为新 URI 基准设置为包含“base”的子模式及其中的所有子模式在处理实例时使用。

在解析以用于“anchor”和解析以用于“href”时,解析“base”模板的过程可能不同,这将在 URI 模板部分详细说明。

5.2. links

模式的“links”属性用于将链接描述对象与实例关联。此属性的值 MUST 为数组,数组中的项目必须是链接描述对象,如下所述。

6. 链接描述对象

链接描述对象 (LDO) 是 RFC 8288 第 2 节 [RFC8288] 中定义的抽象链接模型的序列化。如该文档所述,链接由上下文、关系类型、目标以及可选的目标属性组成。JSON 超级模式的 LDO 提供了所有这些,以及使用 JSON Schema 描述用于以各种方式使用链接的输入的附加功能。

由于使用 URI 模板来标识链接上下文和目标,以及在标识目标时可选地进一步使用客户端输入,因此 LDO 是一个链接模板,当与 JSON 实例文档一起使用时,它可能会解析为多个链接。

LDO 的特定用法,通常涉及跨协议的请求和响应,被称为操作。对于许多协议,在任何给定链接上都可以执行多个操作。协议由目标的 URI 方案指示。请注意,并非所有 URI 方案都指示可用于通信的协议,即使具有指示此类协议的 URI 方案的资源也不必在该协议上可用。

链接描述对象 MUST 为对象,并且 “href” [href]“rel” [rel] 属性 MUST 存在。每个关键字在本节中简要介绍,并在本文档后面的部分提供更多用法说明和综合示例。

6.1. 链接上下文

在 JSON 超级模式中,链接的上下文资源默认情况下是与其关联的子实例(如 JSON Schema 验证规范的第 3 节 [json-schema-validation] 所定义)。这通常不是整个实例文档。可以使用本节中的关键字更改此默认上下文。

根据实例的媒体类型,可能能够或不能为确切的默认上下文资源分配 URI。尤其是 application/json 未定义 URI 片段解析语法,因此普通 JSON 文档中的属性或数组元素无法由 URI 完全标识。当无法生成完整的 URI 时,上下文的位置 SHOULD 通过实例文档的 URI 连同单独的纯字符串 JSON 指针一起传达。

实现 MUST 能够构造链接上下文的 URI,并且(如果需要完整标识)构造一个字符串表示形式的 JSON 指针,如 RFC 6901 第 5 节 [RFC6901] 所示,以代替 URI 片段。在 URI 模板 [uriTemplating] 部分给出了基于 URI 模板构造 URI 的过程。

6.1.1. anchor

此属性设置链接的上下文 URI。该属性的值为 URI 模板 [RFC6570],并且所得的 URI 引用 [RFC3986] MUST 针对实例的基准 URI 解析。

URI 是使用与 “href” [href] 属性所述相同的过程从提供的 URI 模板计算出来的,区别在于 “hrefSchema” [hrefSchema] MUST NOT 应用。与目标 URI 不同,上下文 URI 不接受用户输入。

6.1.2. anchorPointer

此属性更改实例中被视为链接上下文资源的点。该属性的值 MUST 为有效的 JSON 指针,采用 JSON 字符串表示形式,或者为有效的 相对 JSON 指针 [relative-json-pointer],该指针相对于默认上下文进行评估。

虽然使用已知 URI 的备用上下文最好使用 “anchor” [anchor] 关键字设置,但 application/json 缺乏片段标识符语法意味着通常无法使用 URI 在 JSON 实例中更改上下文。

即使在定义 JSON 指针作为片段标识符语法的“+json”媒体类型中,如果默认上下文嵌套在数组中,也无法获取默认上下文在该数组中的位置索引,以便构建指向该同一嵌套 JSON 对象中的另一个属性的指针。这将在示例中演示。

处理此关键字的结果 SHOULD 为 URI 片段(如果实例的媒体类型允许此类片段)。否则,它 MUST 为字符串编码的 JSON 指针。

6.2. 链接关系类型

链接的关系类型标识其语义。它是传达应用程序如何与资源交互的主要手段。

关系定义通常不依赖于媒体类型,鼓励用户利用最合适的现有接受的关系定义。

6.2.1. rel

此属性的值 MUST 为字符串,并且 MUST 为 RFC 8288 第 2.1 节中定义的单个链接关系类型。

此属性是必需的。

6.2.2. “self” 链接

RFC 4287 第 4.2.7.2 节 [RFC4287] 最初定义的那样,“self”链接指示目标 URI 标识与链接上下文等效的资源。在 JSON 超级模式中,“self”链接 MUST 从实例解析,因此“hrefSchema” MUST NOT 存在。

超级模式作者 SHOULD 使用“templateRequired”以确保“self”链接具有使用所需的所有实例数据。

超级模式实现 MUST 识别具有“self”关系类型的链接(其整个当前实例文档作为其上下文)描述用户代理如何与该实例文档所代表的资源交互。

6.2.3. “collection” 和 “item” 链接

RFC 6573 [RFC6573] 定义并注册了“item”和“collection”链接关系类型。JSON 超级模式对由这些类型指示的集合资源施加了额外的语义。

实现 MUST 识别“collection”链接的目标和“item”链接的上下文作为集合。

超媒体中的一种众所周知的模式是使用集合资源创建集合成员并为其分配服务器分配的 URI。如果 URI 方案指示的协议定义了一种特定方法,该方法适合于使用服务器分配的 URI 创建资源,那么由这些链接关系类型标识的集合资源 MUST NOT 定义与创建集合成员的语义冲突的该方法的语义。集合资源 MAY 通过这种协议方法实现项目创建,用户代理 MAY 假设任何此类操作(如果存在)具有项目创建语义。

由于这种方法对应于 JSON 超级模式的数据提交概念,因此链接的 “submissionSchema” [submissionSchema] 字段 SHOULD 与集合项目的表示的模式兼容,如“item”链接的目标资源或“collection”链接的上下文资源的“self”链接所指示。

6.2.4. 使用扩展关系类型

当没有注册的关系(除了“相关”)适用时,鼓励用户按照 RFC 8288 第 2.1.2 节 [RFC8288] 中的描述,自行铸造扩展关系类型。选择链接关系类型 URI 的最简单方法是:要么使用已用于标识系统主要资源的 URI 方案,要么使用人类可读的、不可解析的 URI 方案,例如 RFC 4151 中定义的“tag” [RFC4151]

扩展关系类型 URI 不必可解析,即使使用允许解析的方案。

6.3. 链接目标

目标 URI 模板用于标识链接的目标,并可能使用实例数据。此外,借助 “hrefSchema” [hrefSchema],此模板可以根据客户端输入识别一组可用的目标资源。在 URI 模板 [uriTemplating] 部分中涵盖了使用或不使用客户端输入解析 URI 模板的完整过程。

6.3.1. href

“href”链接描述属性的值是一个模板,用于确定相关资源的目标 URI。实例属性的值必须解析为相对于实例基本 URI 的 URI 引用 [RFC3986]

此属性是必需的。

6.4. 调整 URI 模板解析

本节中的关键字在解析超模式中涉及的所有 URI 模板时使用:“base”、“anchor”和“href”。有关完整的模板解析算法,请参见 URI 模板 [uriTemplating] 部分。

请注意,在解析“base”模板时,解析开始的附加点是正在解析的“href”或“anchor”关键字的附加点,它需要解析“base”模板,而不是“base”关键字本身的附加点。

6.4.1. templatePointers

“templatePointers”链接描述属性的值必须是一个对象。对象中的每个属性值必须是一个有效的 JSON 指针 [RFC6901],或一个有效的 相对 JSON 指针 [relative-json-pointer],它相对于正在解析模板的链接的附加点进行评估。

对于对象中与正在解析的模板中的变量名称匹配的每个属性名称,该属性的值将调整该变量的变量解析的起始位置。与正在解析的模板中的模板变量名称不匹配的属性必须被忽略。

6.4.2. templateRequired

此关键字的值必须是一个数组,并且元素必须是唯一的。每个元素应与链接的 URI 模板中的变量匹配,不进行百分比编码。在完成整个 URI 模板解析过程后,如果此数组中存在的任何变量没有值,则必须不使用该链接。

6.5. 链接目标属性

本节中的所有属性仅供参考。虽然诸如“title”和“description”之类的关键字主要用于向用户展示链接,但那些预测链接交互或响应性质的关键字不应被视为权威性的。目标资源的运行时行为必须在与 LDO 中的目标属性冲突时得到尊重。

6.5.1. title

此属性定义链接的标题。该值必须是一个字符串。

用户代理可以在向用户展示链接时使用此标题。

6.5.2. description

此属性提供了除了标题中提供的之外的更多信息。该值必须是一个字符串。虽然标题最好简短,但描述可用于详细介绍链接的目的和用法。

用户代理可以在向用户展示链接时使用此描述。

6.5.3. targetMediaType

此属性的值表示在获取此资源时预期的媒体类型 RFC 2046 [RFC2046]。此属性值可以是媒体范围,使用与 RFC 7231 第 5.3.2 节 - HTTP“Accept”标头 [RFC7231] 中定义的相同模式。

此属性类似于其他链接序列化格式的“type”属性。用户代理可以使用此信息在链接被跟随之前告知他们向用户呈现的界面,但不得使用此信息来解释结果数据。相反,用户代理必须使用响应中给出的媒体类型进行运行时解释。有关“targetMediaType”误用的详细说明,请参见 “安全问题” [security] 部分。

对于支持内容协商的协议,实现可以使用 “headerSchema” [headerSchema] 中的协议特定信息来描述可能的 targetMediaType。如果同时存在协议特定信息和“targetMediaType”,则“targetMediaType”的值必须与协议特定信息兼容,并且应指示在没有内容协商的情况下将返回的媒体类型。

如果没有此类协议特定信息可用,或者实现无法识别所涉及的协议,则该值应视为“application/json”。

6.5.4. targetSchema

此属性提供了一个预期的模式来描述链接目标的表示形式。根据协议,该模式可能描述或可能不描述对使用该链接执行的任何特定操作的请求或响应。有关如何将此关键字与 HTTP 一起使用的深入讨论,请参见 JSON 超模式和 HTTP [HTTP] 部分。

6.5.5. targetHints

[CREF2]本节试图通过将大多数结构推迟到由 URI 方案指示的协议来在全面性和灵活性之间取得平衡。请注意,资源可以使用具有可解析方案的 URI 来标识,但不能通过该协议访问。虽然目前很宽松,但预计本节将根据草案反馈变得更加明确,并且可能会在未来的草案中发生重大变化。

此属性的值仅供参考。它表示预期通过与目标资源交互而可以发现的信息,通常以协议特定的控制信息或元数据形式出现,例如 HTTP HEAD 或 OPTIONS 请求响应中返回的标头。该协议由“href”URI 方案确定,但请注意,资源不能保证可以通过此类协议访问。

此属性的值应是一个对象。此对象的键应为控制数据字段名称的小写形式。每个值应是一个数组,以便统一处理多值字段。多个值必须以数组形式呈现,而不是以单个字符串形式呈现。

具有不适合作为 JSON 对象表示的控制信息的协议可以通过另一种数据类型(例如数组)来表示。

无法理解为指示协议一部分的值必须被 JSON 超模式实现忽略。应用程序可以使用此类值,但不得假设与其他实现的互操作性。

实现不得假设此对象中包含了所有可发现的信息。客户端应用程序必须正确处理与此属性的值相矛盾的运行时响应。

客户端应用程序不得假设实现将根据此属性的值自动执行任何操作。

有关将此关键字与 HTTP 和类似协议一起使用的指南,请参见 “JSON 超模式和 HTTP” [HTTP]

6.6. 链接输入

有四种方法可以将客户端输入与链接一起使用,每种方法都由一个单独的链接描述对象关键字解决。在执行操作时,用户代理应忽略与其语义无关的模式。

6.6.1. hrefSchema

“hrefSchema”链接描述属性的值必须是一个有效的 JSON 模式。此模式用于验证用户输入或其他用户代理数据,以填充 “href” [href] 中的 URI 模板。

省略“hrefSchema”或将整个模式设置为“false”将阻止任何用户代理数据被接受。

将应用于特定变量的任何子模式设置为 JSON 文字值“false”将阻止接受该单个变量的任何用户代理数据。

对于可以从实例数据中解析的模板变量,如果实例数据针对“hrefSchema”中的所有适用子模式有效,则必须使用它来预先填充该变量的输入数据集。

请注意,即使从实例预先填充数据,"hrefSchema"中该变量的验证模式也不必与应用于实例数据位置的验证模式相同。这允许对用户代理数据使用不同的验证规则,例如支持日期时间输入的拼写月份,但在存储中使用标准日期时间格式。

接受输入后,可能会覆盖预先填充的实例数据,结果数据集必须针对“hrefSchema”的值成功验证。如果它没有,则必须不使用该链接。如果它有效,则“URI 模板”部分中给出的过程将使用此更新的数据集继续。

6.6.2. headerSchema

[CREF3]与“targetHints”一样,此关键字在一定程度上未指定,以鼓励实验和反馈,因为我们试图在灵活性和清晰度之间取得平衡。

如果存在,此属性是协议特定请求标头或类似控制和元数据的模式。此对象的 value 必须是一个有效的 JSON 模式。该协议由“href”URI 方案确定,但请注意,资源不能保证可以通过此类协议访问。该模式仅供参考;目标资源的行为不受其存在的影响。

此关键字的目的是宣传目标资源交互功能,并向用户代理和客户端应用程序指示哪些标头和标头值可能有用。用户代理和客户端应用程序可以使用该模式来验证相关标头,但不得假设缺少标头或值是被禁止使用的。虽然模式作者可以将“additionalProperties”设置为 false,但不推荐这样做,并且不得阻止客户端应用程序或用户代理在发出请求时提供额外的标头。

JSON 数据模型到标头的精确映射取决于协议。但是,在大多数情况下,此模式应指定“object”类型,并且属性名称应为控制数据字段名称的小写形式。有关将此关键字与 HTTP 和类似协议一起使用的详细指南,请参见 “JSON 超模式和 HTTP” [HTTP] 部分。

"headerSchema" 可应用于协议支持的任何请求方法或命令。在生成请求时,用户代理和客户端应用程序 SHOULD 忽略与该请求无关的标头的模式。

6.6.3. 操作目标资源表示

在 JSON 超级模式中,"targetSchema" [targetSchema] 提供了对目标资源表示的非权威描述。客户端应用程序可以使用 "targetSchema" 来构建用于替换或修改表示的输入,或者作为基于补丁媒体类型的构建补丁文档的基准表示。

或者,如果 "targetSchema" 不存在,或者客户端应用程序更喜欢只使用权威信息,则它可以与目标资源进行交互以确认或发现其表示结构。

"targetSchema" 不打算描述链接操作响应,除非响应语义指示它是一个目标资源的表示。在所有情况下,响应本身指示的模式都是权威的。有关详细示例,请参阅 "JSON 超级模式和 HTTP" [HTTP]

6.6.4. 提交数据以供处理

"submissionSchema" [submissionSchema]"submissionMediaType" [submissionMediaType] 关键字描述了目标资源实现的处理功能的域。否则,如上所述,提交模式和媒体类型将被忽略,因为它们与不相关的操作无关。

6.6.4.1. submissionMediaType

如果存在,此属性表示客户端应用程序和用户代理应用于由 "submissionSchema" [submissionSchema] 描述的请求有效负载的媒体类型格式。

省略此关键字的行为与 application/json 的值相同。

请注意,"submissionMediaType" 和 "submissionSchema" 不限于 HTTP URI。 [CREF4]此语句可能会移动到示例的最终位置。

6.6.4.2. submissionSchema

此属性包含一个模式,该模式定义了要根据 "submissionMediaType" 属性编码并发送到目标资源以进行处理的文档的可接受结构。这可以被视为描述目标资源实现的处理功能的域。

这与 "targetSchema" [targetSchema] 属性是不同的概念,它描述了目标信息资源(包括在 PUT 请求中替换资源内容),而 "submissionSchema" 描述了由资源评估的用户提交的请求数据。"submissionSchema" 用于处理具有不一定会根据目标表示定义的有效负载的请求。

省略 "submissionSchema" 的行为与 "true" 的值相同。

7. 实施要求

在高级别,符合的实现将满足以下要求。这些要求中的每一个都在各个关键字部分和关键字组概述中详细介绍。

请注意,有关实现 MUST 如何识别 "self"、"collection" 和 "item" 链接的要求在 链接关系类型 [relationType] 部分中已详细介绍,这里不再赘述。

虽然这不是实施的强制格式,但测试套件中使用的输出格式总结了在使用每个链接之前需要计算的内容

contextUri
上下文资源的完全解析 URI(带方案)。如果上下文不是整个资源,并且存在可用的片段标识符语法,则 URI 包含一个片段。请注意,application/json 没有这种语法。
contextPointer
上下文资源实例中位置的 JSON 指针。如果实例媒体类型支持 JSON 指针作为片段标识符,则此指针将与 "contextUri" 字段片段中编码的指针相同。
rel
链接关系类型,如 LDO 中所示。
targetUri
目标资源的完全解析 URI(带方案)。如果链接接受输入,则只能在提供输入后才能生成此 URI。
hrefInputTemplates
接受输入的链接的,部分解析的 URI 引用列表。列表中的第一个条目是部分解析的 "href"。如果有其他条目,则这些条目是部分解析的 "base" 值,按从最接近的外部到模式根部的顺序排序。在输入中预填充的模板变量在此阶段不会被解析,因为预填充的值可以被覆盖。
hrefPrepopulatedInput
用户代理应使用的数据集,用于在接受客户端输入之前预填充任何输入机制。如果要接受输入,但没有要预填充的字段,则这将是一个空对象。
attachmentPointer
链接所附加到的实例中位置的 JSON 指针。默认情况下,"contextUri" 和 "attachmentUri" 相同,但 "contextUri" 可以通过 LDO 关键字更改,而 "attachmentUri" 则不能。

其他未参与生成上述信息的 LDO 关键字在生成测试套件的输出时将完全按照它们出现时的状态进行包含。除非特别相关,否则这些字段将不再详细介绍。

7.1. 链接发现和查找

在使用链接之前,必须通过将超模式应用于实例并找到所有适用且有效的链接来发现它们。请注意,除了收集有效链接之外,还需要找到解析每个 LDO 的 URI 模板所需的任何 "base" [base] 值,并将它们通过对实施的 URI 模板解析过程最有用的任何机制与 LDO 相关联。

实施 MUST 支持通过其附件指针或上下文指针查找链接,无论是通过执行查找还是通过提供确定了两个指针的所有链接集,以便用户代理可以自行实现查找。

在通过上下文指针执行查找时,附加到同一数组中的元素的链接 MUST 按与附加到它们的数组元素相同的顺序返回。

7.2. URI 模板

三个超级模式关键字是 URI 模板 [RFC6570]:"base"、"anchor" 和 "href"。每个关键字都分别解析为 URI 引用,然后锚点或 href URI 引用相对于基准进行解析(该基准本身根据需要相对于较早的基准进行解析,这些基准最初是从 URI 模板解析为 URI 引用)。

所有三个关键字都共享相同的算法,用于从实例数据中解析变量,该算法使用 "templatePointers" 和 "templateRequired" 关键字。在解析 "href" 时,它和任何用于解析为绝对 URI 的 "base" 模板,该算法被修改为可以选择性地接受基于 "hrefSchema" 关键字的用户输入。

对于每个 URI 模板 (T),以下伪代码描述了将 T 解析为 URI 引用 (R) 的算法。为了便于说明,

此算法应该首先应用于 "href" 或 "anchor",然后根据需要应用于每个后续的 "base"。顺序很重要,因为无法始终确定模板是否会解析为完整 URI 或 URI 引用。

从高级别来看,该算法的英文描述如下

  1. 从实例中填充模板变量数据
  2. 如果需要输入,则接受输入
  3. 检查所有必需变量是否都有值
  4. 将值编码为字符串并填写模板

以下是作为伪代码的高级算法。 "T" 来自 LDO 中的 "href" 或 "anchor",或者来自包含模式中的 "base"。每个步骤的伪代码如下。"initialTemplateKeyword" 指示开始该过程的两个关键字中的哪一个(因为 "base" 总是被解析以完成其中一个关键字的解析)。

templateData = populateDataFromInstance(T, ldo, instance)

if initialTemplateKeyword == "href" and ldo.hrefSchema exists:
    inputData = acceptInput(ldo, instance, templateData)
    for varname in inputData:
        templateData[varname] = inputData[varname]

for varname in ldo.templateRequired:
    if not exists templateData[varname]
        fatal("Missing required variable(s)")

templateData = stringEncode(templateData)
R = rfc6570ResolutionAlgorithm(T, templateData)

                    

7.2.1. 从实例中填充模板数据

此步骤查看实例中不同位置的变量值。对于每个变量

  1. 如果变量出现在该关键字的值中,则使用 "templatePointers" 查找值
  2. 否则,在链接所附加到的实例位置中查找与变量匹配的属性名称
  3. 在任何一种情况下,如果该位置有值,则将其放入模板解析数据集

for varname in T:
    varname = rfc3986PercentDecode(varname)
    if varname in ldo.templatePointers:
        valuePointer = templatePointers[varname]
        if valuePointer is relative:
            valuePointer = resolveRelative(attachmentPointer,
                                           valuePointer)
    else
        valuePointer = attachmentPointer + "/" + varname

    value = instance.valueAt(valuePointer)
    if value is defined:
        templateData[varname] = value

                        

7.2.2. 接受模板数据的输入

此步骤比较复杂,因为它需要支持多种情况。一些变量会禁止输入,而另一些则允许输入。有些变量将具有需要在输入界面中显示的初始值,而有些变量则没有。

  1. 确定哪些变量可以接受输入
  2. 如果模板解析数据集有值,则预填充输入数据集
  3. 接受输入(显示 Web 表单,进行回调等)
  4. 验证输入数据集(不是模板解析数据集)
  5. 将输入放入模板解析数据集,覆盖任何现有值

"InputForm" 表示任何适合的输入机制。这可能是一个文字 Web 表单,也可能是一个更具程序性的结构,例如接受特定字段和数据类型的回调函数,并具有给定的初始值(如果有)。

form = new InputForm()
for varname in T:
    useField = true
    useInitialData = true
    for schema in getApplicableSchemas(ldo.hrefSchema,
                                       "/" + varname):
        if schema is false:
            useField = false
            break

        if varname in templateData and
           not isValid(templateData[varname], schema)):
            useInitialData = false
            break

    if useField:
        if useInitialData:
            form.addInputFieldFor(varname, ldo.hrefSchema,
                                  templateData[varname])
        else:
            form.addInputFieldFor(varname, ldo.hrefSchema)

inputData = form.acceptInput()

if not isValid(inputData, hrefSchema):
    fatal("Input invalid, link is not usable")

return inputData:

                        

7.2.3. 将数据编码为字符串

本节非常简单,将文字转换为其名称作为字符串,并将数字以最明显的方式转换为字符串,并在 URI 中使用时根据需要进行百分比编码。

for varname in templateData:
    value = templateData[varname]
    if value is true:
        templateData[varname] = "true"
    else if value is false:
        temlateData[varname] = "false"
    else if value is null:
        templateData[varname] = "null"
    else if value is a number:
        templateData[varname] =
            bestEffortOriginalJsonString(value)
    else:
        templateData[varname] = rfc3986PercentEncode(value)

                        

在某些软件环境中,数字的原始 JSON 表示形式将不可用(无法区分 1.0 和 1),因此应使用任何合理的表示形式。模式和 API 作者应牢记这一点,并在精确的表示形式很重要的情况下使用其他类型(例如字符串或布尔值)。如果数字作为字符串形式提供为输入,则 SHOULD 使用用作输入的字符串。

7.3. 提供对 LDO 关键字的访问

对于给定的链接,实施 MUST 将所有目标属性关键字的值直接提供给用户代理。实施 MAY 提供用于使用此信息的附加接口,如每个关键字部分中所述。

对于给定的链接,实施 MUST 将每个输入模式关键字的值直接提供给用户代理。

为了鼓励对 URI 模板解析过程进行封装,实施 MAY 省略仅用于构造 URI 的 LDO 关键字。但是,实施 MUST 提供对链接关系类型的访问。

用户代理 SHOULD 提供无法识别的关键字,否则 MUST 忽略它们。

7.4. 请求

超模式实现 SHOULD 提供访问构建任何有效请求到目标资源所需的所有信息。

LDO 可以表达执行链接上任何操作所需的所有信息。本节解释了用户代理应该检查哪些超模式字段以根据任何组合的实例数据和客户端输入来构建请求。超模式实现本身并不期望构建和发送请求。

目标 URI 构建规则,包括用于接受输入的 "hrefSchema",对于所有可能的请求都是相同的。

不携带主体负载的请求不需要额外的关键字支持。

以目标表示形式作为负载的请求 SHOULD 使用 "targetSchema" 和 "targetMediaType" 关键字进行输入描述和负载验证。如果协议允许操作采用基于由媒体类型修改的表示形式的负载(例如,补丁媒体类型),那么此类媒体类型 SHOULD 通过 "targetHints" 以协议特定的方式指示。

采用非目标资源表示形式的负载的请求 SHOULD 使用 "submissionSchema" 和 "submissionMediaType" 关键字进行输入描述和负载验证。超媒体中使用的协议通常每个链接只支持一个此类非表示形式操作。

通过单个超媒体协议操作管道化许多具有任意不同请求结构的应用程序操作的 RPC 系统超出了 JSON 超模式等超媒体格式的范围。

7.5. 响应

作为一种超媒体格式,JSON 超模式关注描述资源,包括以足够的细节描述其链接,以便进行所有有效的请求。它不关注直接描述这些请求的所有可能响应。

与任何超媒体系统一样,响应应是自描述的。在超模式的上下文中,这意味着每个响应 MUST 链接其自己的超模式。虽然由目标资源的表示形式组成的响应预计将根据 "targetSchema" 和 "targetMediaType" 有效,但这些关键字仅为建议,如果与响应本身相矛盾,MUST 忽略它们。

其他响应,包括错误响应、复杂重定向和处理状态表示 SHOULD 也链接到它们自己的模式并使用适当的媒体类型(例如,"application/problem+json" [RFC7807] 用于错误)。某些错误可能不会链接模式,因为它们是由不了解超模式的中介而不是由源生成。

用户代理预计能够理解协议状态码和响应媒体类型,足以处理常见情况,并向客户端应用程序提供足够的信息来处理特定于域的响应。

在设计时静态映射所有可能的响应及其模式超出了 JSON 超模式的范围,但可能在构建在超模式上的其他 JSON 模式词汇表的范围内(请参阅 附录 A.3)。

7.6. 流式解析器

根据其上下文发现链接或使用链接上下文识别集合的要求在与流式解析器一起使用时提出了独特的挑战。在不处理整个模式和实例文档的情况下,不可能权威地满足这些要求。

此类实现 MAY 选择根据迄今为止处理的数据返回非权威答案。在提供这种方法时,实现 MUST 清楚说明响应的性质,并且 MUST 提供一个选项来阻止并等待直到所有数据都被处理,并且可以返回权威答案。

8. JSON 超模式和 HTTP

虽然 JSON 超模式是一种超媒体格式,因此与协议无关,但预计它最常见的用途是在 HTTP 系统中,或者在使用 CoAP 等明确类似于 HTTP 的协议的系统中。

本节提供有关如何将每个常见的 HTTP 方法与链接一起使用以及集合资源如何对 HTTP POST 强加额外约束的指导。此外,还提供有关提示 HTTP 响应头值和描述与给定资源相关的可能的 HTTP 请求头的指导。

JSON 模式核心规范的第 11 节 [json-schema] 提供了有关在超媒体系统中将实例链接到其模式的指导。这可以通过网络可访问的模式来完成,或者可能只是识别预先打包在客户端应用程序中的模式。JSON 超模式有意不限制这种机制,尽管 RECOMMENDED 使用核心规范中概述的技术,只要有可能。

8.1. 每个目标和关系类型一个链接

链接描述对象不会直接指示目标资源支持哪些操作,例如 HTTP 方法。相反,操作应该主要从链接 关系类型 [rel] 和 URI 方案推断。

这意味着对于每个目标资源和链接关系类型对,模式作者 SHOULD 只定义一个 LDO。虽然可以使用 "allow" 和 "targetHints" 来重复具有不同 HTTP 方法标记为允许的关系类型和目标对,但这 NOT RECOMMENDED 并且可能无法得到符合实现的良好支持。

如本节所述,所有使用每个 HTTP 方法所需的信息都可以在单个 LDO 中传达。"targetHints" 中的 "allow" 字段仅用于提示支持哪些操作,而不是单独定义每个操作。

但是请注意,资源可能始终在运行时拒绝操作,例如由于授权失败,或者由于控制操作可用性的其他应用程序状态。

8.2. "targetSchema" 和 HTTP

"targetSchema" 描述了链接目标端的资源,而 "targetMediaType" 定义了该资源的媒体类型。对于 HTTP 链接,"headerSchema" 也可以用于描述用于 "Accept" 请求头的有效值,这可以支持多种媒体类型或媒体范围。当两种指示目标媒体类型的方式都存在时,"targetMediaType" SHOULD 指示默认表示媒体类型,而 "headerSchema" 中 "accept" 的模式 SHOULD 包括默认值以及可以请求的任何备用媒体类型或媒体范围。

由于许多 HTTP 方法的语义是根据目标资源定义的,因此 "targetSchema" 用于几种 HTTP 方法的请求和/或响应。特别是,"targetSchema" 建议客户端应用程序可以预期 HTTP GET 的响应或任何 "Content-Location" 头等于请求 URI 的响应,以及如果客户端应用程序在 HTTP PUT 请求中替换资源,客户端应用程序应该发送什么。这些相关性由 RFC 7231 的第 4.3.1 节 - "GET"、第 4.3.4 节 "PUT" 和第 3.1.4.2 节 "Content-Location" [RFC7231] 定义。

根据 RFC 5789 [RFC5789],HTTP PATCH 的请求结构由 "targetSchema" 和请求媒体类型的组合决定,请求媒体类型由 "Accept-Patch" 头传达,"Accept-Patch" 头可能包含在 "targetHints" 中。适合用于 PATCH 的媒体类型定义了一种语法来表达对文档的更改,该语法可以应用于 "targetSchema" 描述的表示形式以确定语法上有效的请求有效负载集。通常,验证 PATCH 请求的最简单方法是应用它并将结果验证为正常的表示形式。

8.3. HTTP POST 和 "submission*" 关键字

JSON 超模式允许资源处理除了或代替处理目标表示形式的任意数据。此任意数据由 "submissionSchema" 和 "submissionMediaType" 关键字描述。在 HTTP 的情况下,POST 方法是唯一处理此类数据的 POST 方法。虽然在使用 POST 与集合方面存在某些约定,但 POST 请求的语义由目标资源而不是 HTTP 定义。

除了协议中立的 "submission*" 关键字(请参阅 第 9.3 节 以获取非 HTTP 示例)之外,"Accept-Post" 头可以用于指定必要的媒体类型,并且 MAY 通过 "targetHints" 字段进行宣传。 [CREF5]如果两者都使用会发生什么?此外,"submissionSchema" 是 MUST 支持的,而 "targetHints" 至多是 SHOULD。但禁止在 "targetHints" 中使用 "Accept-Post" 似乎不正确。

除了 201 或带有 "Content-Location" 设置的 200 之外的 POST 的成功响应也没有 HTTP 定义的语义。与所有 HTTP 响应一样,响应中的任何表示形式都应链接到其自己的超模式以指示如何对其进行处理。如 附录 A.2 中所述,将超链接与所有可能的运行操作响应连接不在 JSON 超模式的范围内。

8.4. 使用 "targetHints" 优化 HTTP 可发现性

[CREF6]最好也包括一个包含 CoAP 示例的部分。

HTTP 响应头信息 JSON 序列化 SHOULD 遵循正在进行的工作中建立的指南 "HTTP 头字段值的 JSON 编码" [I-D.reschke-http-jfv]。该文档示例中所示的方法 SHOULD 在可能的情况下应用于其他类似结构的标题。

所有可能的 HTTP 方法响应的标题都共享 "headerSchema"。特别是,出现在 HEAD 响应中的标题和出现在 OPTIONS 响应中的标题都可能出现。在 "headerSchema" 中不区分哪种方法响应包含哪个标题。

RECOMMENDED 模式作者在适用时为以下类型 HTTP 标题的值提供提示

通常,在不同时间可能具有不同值的标题 SHOULD NOT 包含在 "targetHints" 中。

8.5. 使用 "headerSchema" 宣传 HTTP 功能

模式 SHOULD 被编写为描述遵循正在进行的工作中建立的指南的 JSON 序列化 "HTTP 头字段值的 JSON 编码" [I-D.reschke-http-jfv]。该文档示例中所示的方法 SHOULD 在可能的情况下应用于其他类似结构的标题。

RECOMMENDED 模式作者在适用时描述以下类型 HTTP 标题的可用用法

诸如缓存控制和条件请求标题之类的标题通常由中介而不是资源实现,因此通常对描述没有用。虽然资源必须提供使用条件请求所需的信息,但此类标题和相关响应的运行时处理不是特定于资源的。

8.6. 通过集合创建资源

使用 HTTP 或明确类似于 HTTP 的协议(如 CoAP)时,这是通过将要创建的单个资源的表示形式 POST 到集合资源来完成的。识别集合和项目资源的过程在 第 6.2.3 节 中描述。

8.7. 内容协商和模式演进

JSON 超模式简化了 HTTP 内容协商,并允许使用主动和被动策略的混合。如上所述,超模式可以包含 HTTP 标题(如 "Accept"、"Accept-Charset"、"Accept-Language" 等)的模式,使用 "headerSchema" 关键字。用户代理或客户端应用程序可以使用此模式中的信息,例如支持语言的枚举列表,来代替发出初始请求以启动被动协商过程。

通过这种方式,设置这些标题的主动内容协商技术可以从服务器有关哪些值可能的信息中得到通知,类似于检查被动协商中的备选列表。

对于允许在媒体类型参数中指定模式的媒体类型,请求中发送的或在“headerSchema”中宣传的“Accept”值可以包含预期协商表示形式符合的模式的 URI。模式参数在内容协商中的一种可能用途是,如果资源随时间推移已符合多个不同的模式版本。客户端应用程序可以通过这种方式在“Accept”标头中指示它理解的版本。

9. 示例

本节展示了用于构建 URI 和 JSON 指针的关键字的使用方式。结果以测试套件中使用的格式显示。[CREF7]需要发布并链接它,但这对于此时正在审查事物的人来说应该是非常直观的。

大多数其他关键字要么很直观(“title”和“description”),要么应用于特定类型输入、请求或响应的验证,要么具有特定于协议的行为。演示 HTTP 用法的示例在 附录 [HTTP] 中提供。

9.1. 入口点链接,无模板

在本例中,我们将假设一个示例 API,其文档化的入口点 URI 为 https://example.com,这是一个空的 JSON 对象,其中包含一个指向模式的链接。这里,入口点本身没有数据,只存在于提供一组初始链接。

GET https://api.example.com HTTP/1.1

200 OK
Content-Type: application/json
Link: <https://schema.example.com/entry> rel=describedBy
{}

                    

链接的超模式定义了 API 的基本 URI 并提供了两个链接:一个指向 API 文档的“about”链接,以及一个指示这是基本 URI 模式自身的“self”链接。在本例中,基本 URI 也是入口点 URI。

{
    "$id": "https://schema.example.com/entry",
    "$schema": "https://json-schema.fullstack.org.cn/draft-07-wip/hyper-schema#",
    "base": "https://api.example.com",
    "links": [
        {
            "rel": "self",
            "href": ""
        }, {
            "rel": "about",
            "href": "/docs"
        }
    ]
}
                    

这些是最简单的链接,只有关系类型和一个没有模板变量的“href”。它们解析如下:

[
    {
        "contextUri": "https://api.example.com",
        "contextPointer": "",
        "rel": "self",
        "targetUri": "https://api.example.com",
        "attachmentPointer": ""
    },
    {
        "contextUri": "https://api.example.com",
        "contextPointer": "",
        "rel": "about",
        "targetUri": "https://api.example.com/docs",
        "attachmentPointer": ""
    }
]
                    

附件指针是根指针(对于实例的空对象来说,唯一的可能性)。上下文 URI 是默认的,即请求的文档。由于 application/json 不允许使用片段,因此上下文指针对于完整描述上下文是必要的。它的默认行为与附件指针相同。

9.2. 单独标识的资源

让我们将“things”添加到我们的系统中,从单个“thing”开始

{
    "$id": "https://schema.example.com/thing",
    "$schema": "https://json-schema.fullstack.org.cn/draft-07-wip/hyper-schema#",
    "base": "https://api.example.com",
    "type": "object",
    "required": ["data"],
    "properties": {
        "id": {"$ref": "#/definitions/id"},
        "data": true
    },
    "links": [
        {
            "rel": "self",
            "href": "things/{id}",
            "templateRequired": ["id"],
            "targetSchema": {"$ref": "#"}
        }
    ],
    "definitions": {
        "id": {
            "type": "integer",
            "minimum": 1,
            "readOnly": true
        }
    }
}
                    

我们的“thing”有一个服务器分配的 ID,它是在构建“self”链接时必需的。它还有一个“data”字段,可以是任何类型。 “definitions”部分的原因将在下一个示例中清楚地解释。

请注意,“id”不是验证模式要求的,但它是“self”链接要求的。这是有道理的:只有在创建“thing”并由服务器分配 ID 后,它才具有 URI。但是,您可以将此模式与仅包含 data 字段的实例一起使用,这允许您验证即将创建的“thing”实例。

让我们在入口点模式中添加一个链接,如果您能提供它的 ID 作为输入,则允许您直接跳转到特定事物。为了节省空间,只显示新的 LDO。与“self”和“about”不同,没有关于假设事物的 IANA 注册的关系,因此使用 “tag:” URI 方案 [RFC4151] 定义扩展关系。

{
    "rel": "tag:rel.example.com,2017:thing",
    "href": "things/{id}",
    "hrefSchema": {
        "required": ["id"],
        "properties": {
            "id": {"$ref": "thing#/definitions/id"}
        }
    },
    "targetSchema": {"$ref": "thing#"}
}
                    

这里的“href”值相同,但其他所有内容都不同。回想一下,实例是一个空对象,因此“id”无法从实例数据中解析。相反,它作为客户端输入是必需的。此 LDO 也可以使用“templateRequired”,但在“hrefSchema”中使用“required”时,它不是严格必要的。在“hrefSchema”中未将“id”标记为必需的情况下提供“templateRequired”会导致错误,因为客户端输入是解析此链接的唯一可能来源。

9.3. 提交有效负载并接受 URI 输入

此示例涵盖了对非表示输入使用“submission”字段,以及与使用输入解析 URI 模板一起使用它们。与 HTML 表单不同,HTML 表单需要构建 URI 或发送有效负载,但不能同时执行这两者,JSON 超模式可以描述在同一链接上对相同操作执行两种类型的输入。

“submissionSchema”和“submissionMediaType”字段用于描述不是目标资源表示的有效负载。当与“http(s)://”URI 一起使用时,它们通常指的是 POST 请求有效负载,如 HTTP 用法附录 [HTTP] 中所见。

在本例中,我们使用“mailto:”URI,它根据 RFC 6068,第 3 节” [RFC6068],不提供任何用于检索资源的操作。它只能用于构建发送邮件的邮件。由于没有可检索、可替换或可删除的目标资源的概念,因此不使用“targetSchema”和“targetMediaType”。“submissionSchema”和“submissionMediaType”描述了非表示有效负载。

我们使用“submissionMediaType”指示 multipart/alternative 有效负载格式,提供同一数据的两种表示形式(HTML 和纯文本)。由于 multipart/alternative 邮件是有序序列(最后一个部分是最优选的备选方案),因此我们将序列建模为“submissionSchema”中的数组。由于每个部分本身都是具有媒体类型的文档,因此我们将数组中的每个项目建模为字符串,并使用“contentMediaType”指示字符串中的格式。

请注意,诸如 multipart/form-data 之类的媒体类型将名称与每个部分相关联,并且没有排序,应将其建模为 JSON 对象而不是数组。

请注意,某些行已换行以适合此文档的宽度限制。

{
    "$id": "https://schema.example.com/interesting-stuff",
    "$schema": "https://json-schema.fullstack.org.cn/draft-07-wip/hyper-schema#",
    "required": ["stuffWorthEmailingAbout", "email", "title"],
    "properties": {
        "title": {
            "type": "string"
        },
        "stuffWorthEmailingAbout": {
            "type": "string"
        },
        "email": {
            "type": "string",
            "format": "email"
        },
        "cc": false
    },
    "links": [
        {
            "rel": "author",
            "href": "mailto:{email}?subject={title}{&cc}",
            "templateRequired": ["email"],
            "hrefSchema": {
                "required": ["title"],
                "properties": {
                    "title": {
                        "type": "string"
                    },
                    "cc": {
                        "type": "string",
                        "format": "email"
                    },
                    "email": false
                }
            },
            "submissionMediaType":
                    "multipart/alternative; boundary=ab2",
            "submissionSchema": {
                "type": "array",
                "items": [
                    {
                        "type": "string",
                        "contentMediaType":
                                "text/plain; charset=utf8"
                    },
                    {
                        "type": "string",
                        "contentMediaType": "text/html"
                    }
                ],
                "minItems": 2
            }
        }
    ]
}
                    

对于 URI 参数,这三个都演示了解析输入的不同方式

email
此变量在“templateRequired”中的存在意味着它必须解析才能使用模板。由于在“hrefSchema”中分配给它的“false”模式将其从输入数据集排除,因此它必须从实例中解析。
title
与该变量匹配的实例字段是必需的,并且也允许在输入数据中使用。因此,它的实例值在接受客户端输入之前用于预填充输入数据集。客户端应用程序可以选择保留实例值。由于此字段在“hrefSchema”中是必需的,因此客户端应用程序无法删除它(尽管它可以将其设置为一个空字符串)。
cc
在主模式中为其设置的“false”模式阻止此字段具有实例值。如果它完全存在,它必须来自客户端输入。由于它在“hrefSchema”中不是必需的,因此它可能根本没有被使用。

因此,给定从“https://api.example.com/stuff”检索到的以下实例:

{
    "title": "The Awesome Thing",
    "stuffWorthEmailingAbout": "Lots of text here...",
    "email": "[email protected]"
}
                    

我们可以在向客户端应用程序请求输入之前,部分解析链接,如下所示。

{
    "contextUri": "https://api.example.com/stuff",
    "contextPointer": "",
    "rel": "author",
    "hrefInputTemplates": [
      "mailto:[email protected]?subject={title}{&cc}"
    ],
    "hrefPrepopulatedInput": {
        "title": "The Really Awesome Thing"
    },
    "attachmentPointer": ""
}
                    

请注意“href*”关键字代替“targetUri”。这三种是涵盖不同类型输入的“targetUri”值的可能类型。以下是每个示例:

无额外或更改的输入
"mailto:[email protected]?subject=The%20Awesome%20Thing"
将“title”更改为“your work”
"mailto:[email protected]?subject=your%20work"
更改标题并添加一个“cc”为 "[email protected]"
"mailto:[email protected]?subject=your%20work&[email protected]"

9.4. “anchor”、“base”和 URI 模板解析

链接是类型化的连接,从上下文资源连接到目标资源。较旧的链接序列化支持一个“rev”关键字,该关键字使用与“rel”相同的链接关系类型,但反转语义。这已被长期弃用,因此 JSON 超模式不支持它。“anchor”更改上下文 URI 的能力可用于反转链接的方向。它还可用于描述两个资源之间的链接,这两个资源都不是当前资源。

例如,存在一个 IANA 注册的“up”关系,但没有“down”。在 HTTP Link 标头中,您可以将“down”实现为 "rev": "up"

首先让我们看看如何在 HTTP 中完成此操作,展示一个“self”链接和两个语义上相同的链接,一个使用“rev”: “up”,另一个使用“anchor”和“rel”: “up”(由于格式限制,行已换行)。

GET https://api.example.com/trees/1/nodes/123 HTTP/1.1

200 OK
Content-Type: application/json
Link: <https://api.example.com/trees/1/nodes/123> rel=self
Link: <https://api.example.com/trees/1/nodes/123> rel=up
        anchor=<https://api.example.com/trees/1/nodes/456>
Link: <https://api.example.com/trees/1/nodes/456> rev=up
{
    "id": 123,
    "treeId": 1,
    "childIds": [456]
}

                    

请注意,“rel=up”链接的目标 URI 与“rel=self”链接相同,并将“anchor”(标识链接的上下文)设置为子项的 URI。当存在“self”链接时,此类反向链接很容易被工具检测到。

以下超模式应用于上面的响应中的实例,将产生相同的“self”链接和使用“anchor”的“up”链接。它还展示了模板化的“base”URI 的使用,以及“templatePointers”中绝对和相对 JSON 指针的组合。

    "base": "trees/{treeId}",
    "properties": {
        "id": {"type": "integer"},
        "treeId": {"type": "integer"},
        "childIds": {
            "type": "array",
            "items": {
                "type": "integer",
                "links": [
                    {
                        "anchor": "nodes/{thisNodeId}",
                        "rel": "up",
                        "href": "nodes/{childId}",
                        "templatePointers": {
                            "thisNodeId": "/id",
                            "childId": "0"
                        }
                    }
                ]
            }
        }
    },
    "links": [
        {
            "rel": "self",
            "href": "nodes/{id}"
        }
    ]
}
                    

对目标 (“href”) 和上下文 (“anchor”) URI 的评估方式对于“base”模板来说是相同的。

请注意两种不同类型的 templatePointers 的使用。“thisNodeId”映射到一个绝对 JSON 指针,“/id”,而“childId”映射到一个相对指针,“0”,它指示当前项目的价值。绝对 JSON 指针不支持任何形式的通配符,因此无法指定类似“当前项目”的概念,而无需相对 JSON 指针。

9.5. 集合

在许多系统中,单个资源被分组到集合中。这些集合通常还提供一种方法,使用服务器分配的标识符来创建单个项目资源。

在本例中,我们将重新使用前面部分所示的单个事物模式。为了方便起见,这里将其重复一遍,并添加了一个“collection”链接,其中包含一个指向我们将要介绍的集合模式的“targetSchema”引用。

{
    "$id": "https://schema.example.com/thing",
    "$schema": "https://json-schema.fullstack.org.cn/draft-07-wip/hyper-schema#",
    "base": "https://api.example.com",
    "type": "object",
    "required": ["data"],
    "properties": {
        "id": {"$ref": "#/definitions/id"},
        "data": true
    },
    "links": [
        {
            "rel": "self",
            "href": "things/{id}",
            "templateRequired": ["id"],
            "targetSchema": {"$ref": "#"}
        }, {
            "rel": "collection",
            "href": "/things",
            "targetSchema": {"$ref": "thing-collection#"},
            "submissionSchema": {"$ref": "#"}
        }
    ],
    "definitions": {
        "id": {
            "type": "integer",
            "minimum": 1,
            "readOnly": true
        }
    }
}
                    

“collection”链接对于所有项目都是相同的,因此没有 URI 模板变量。“submissionSchema”是项目本身的模式。如 第 6.2.3 节 所述,如果“collection”链接支持提交机制(HTTP 中的 POST),那么它必须实现项目创建语义。因此,“submissionSchema”是通过此链接创建“thing”的模式。

现在我们想描述“thing”的集合。此模式描述了一个集合,其中每个项目表示都与单个“thing”表示相同。虽然许多集合表示只包含项目表示的子集,但本例使用全部表示来减少涉及的模式数量。实际的集合项目显示为对象中的数组,因为我们将在下一个示例中向对象添加更多字段。

{
    "$id": "https://schema.example.com/thing-collection",
    "$schema": "https://json-schema.fullstack.org.cn/draft-07-wip/hyper-schema#",
    "base": "https://api.example.com",
    "type": "object",
    "required": ["elements"],
    "properties": {
        "elements": {
            "type": "array",
            "items": {
                "allOf": [{"$ref": "thing#"}],
                "links": [
                    {
                        "anchorPointer": "",
                        "rel": "item",
                        "href": "things/{id}",
                        "templateRequired": ["id"],
                        "targetSchema": {"$ref": "thing#"}
                    }
                ]
            }
        }
    },
    "links": [
        {
            "rel": "self",
            "href": "things",
            "targetSchema": {"$ref": "#"},
            "submissionSchema": {"$ref": "thing"}
        }
    ]
}
                    
{
    "elements": [
        {"id": 12345, "data": {}},
        {"id": 67890, "data": {}}
    ]
}
                    

以下是应用于此实例的所有链接,包括在引用的单个“thing”模式中定义的链接:

[
    {
        "contextUri": "https://api.example.com/things",
        "contextPointer": "",
        "rel": "self",
        "targetUri": "https://api.example.com/things",
        "attachmentPointer": ""
    },
    {
        "contextUri": "https://api.example.com/things",
        "contextPointer": "/elements/0",
        "rel": "self",
        "targetUri": "https://api.example.com/things/12345",
        "attachmentPointer": "/elements/0"
    },
    {
        "contextUri": "https://api.example.com/things",
        "contextPointer": "/elements/1",
        "rel": "self",
        "targetUri": "https://api.example.com/things/67890",
        "attachmentPointer": "/elements/1"
    },
    {
        "contextUri": "https://api.example.com/things",
        "contextPointer": "",
        "rel": "item",
        "targetUri": "https://api.example.com/things/12345",
        "attachmentPointer": "/elements/0"
    },
    {
        "contextUri": "https://api.example.com/things",
        "contextPointer": "",
        "rel": "item",
        "targetUri": "https://api.example.com/things/67890",
        "attachmentPointer": "/elements/1"
    },
    {
        "contextUri": "https://api.example.com/things",
        "contextPointer": "/elements/0",
        "rel": "collection",
        "targetUri": "https://api.example.com/things",
        "attachmentPointer": "/elements/0"
    },
    {
        "contextUri": "https://api.example.com/things",
        "contextPointer": "/elements/1",
        "rel": "collection",
        "targetUri": "https://api.example.com/things",
        "attachmentPointer": "/elements/1"
    }
]

                    

在所有情况下,上下文 URI 都显示为媒体类型 application/json 的实例,它不支持片段。如果实例媒体类型是 application/instance+json(支持 JSON 指针片段),那么上下文 URI 将包含与上下文指针字段相同的片段。对于 application/json 和其他没有片段的媒体类型,考虑上下文指针和上下文 URI 都是至关重要的。

存在三个“self”链接,一个用于集合,一个用于“elements”数组中的每个项目。项目“self”链接是在引用的单个“thing”模式中定义的,该模式使用“$ref”引用。这三个链接可以通过它们的上下文或附件指针来区分。我们将重新审视集合的“self”链接的“submissionSchema”,见 第 9.5.2 节

存在两个“item”链接,一个用于“elements”数组中的每个项目。与“self”链接不同,这些链接仅在集合模式中定义。它们中的每一个都具有与共享相同附件指针的相应“self”链接相同的目标 URI。但是,它们都有不同的上下文指针。“self”链接的上下文是“elements”中的条目,而“item”链接的上下文始终是整个集合,而不管具体项目是什么。

最后,有两个“collection”链接,每个“elements”中的项目各有一个。在单个项目模式中,这些链接会以项目资源作为上下文。当从集合模式中引用时,上下文是相关“thing”在“elements”数组中的位置,而不是该“thing”自身独立的资源 URI。

集合链接具有相同的目标 URI,因为只有一个相关的集合 URI。虽然将这两个链接都计算为构造链接的完整集合的一部分似乎没有用,但在按需构造链接时,这种安排意味着无论您正在处理哪个“elements”条目,都会有一个“collection”链接定义近在咫尺。

9.5.1. 分页

这里我们在集合中添加了分页。有一个“meta”部分来保存有关当前页、下一页和上一页的信息。大多数模式与上一节相同,已被省略。只有新字段以及新或(在主“self”链接的情况下)已更改的链接将完整显示。

{
    "properties": {
        "elements": {
            ...
        },
        "meta": {
            "type": "object",
            "properties": {
                "prev": {"$ref": "#/definitions/pagination"},
                "current": {"$ref": "#/definitions/pagination"},
                "next": {"$ref": "#/definitions/pagination"}
            }
        }
    },
    "links": [
        {
            "rel": "self",
            "href": "things{?offset,limit}",
            "templateRequired": ["offset", "limit"],
            "templatePointers": {
                "offset": "/meta/current/offset",
                "limit": "/meta/current/limit"
            },
            "targetSchema": {"$ref": "#"}
        }, {
            "rel": "prev",
            "href": "things{?offset,limit}",
            "templateRequired": ["offset", "limit"],
            "templatePointers": {
                "offset": "/meta/prev/offset",
                "limit": "/meta/prev/limit"
            },
            "targetSchema": {"$ref": "#"}
        }, {
            "rel": "next",
            "href": "things{?offset,limit}",
            "templateRequired": ["offset", "limit"],
            "templatePointers": {
                "offset": "/meta/next/offset",
                "limit": "/meta/next/limit"
            },
            "targetSchema": {"$ref": "#"}
        }
    ],
    "definitions": {
        "pagination": {
            "type": "object",
            "properties": {
                "offset": {
                    "type": "integer",
                    "minimum": 0,
                    "default": 0
                },
                "limit": {
                    "type": "integer",
                    "minimum": 1,
                    "maximum": 100,
                    "default": 10
                }
            }
        }
    }
}
                        

请注意,“self”链接包含生成精确表示的分页查询,而不是指向允许通过输入选择页面的集合的通用链接。

鉴于此实例

{
    "elements": [
        {"id": 12345, "data": {}},
        {"id": 67890, "data": {}}
    ],
    "meta": {
        "current": {
            "offset": 0,
            "limit": 2
        },
        "next": {
            "offset": 3,
            "limit": 2
        }
    }
}
                        

以下是适用于此实例的所有链接,这些链接要么没有出现在前面的示例中,要么是在添加分页后发生了更改。

[
    {
        "contextUri": "https://api.example.com/things",
        "contextPointer": "",
        "rel": "self",
        "targetUri":
            "https://api.example.com/things?offset=20,limit=2",
        "attachmentPointer": ""
    },
    {
        "contextUri": "https://api.example.com/things",
        "contextPointer": "",
        "rel": "next",
        "targetUri":
            "https://api.example.com/things?offset=22,limit=2",
        "attachmentPointer": ""
    }
]
                        

请注意,输出中没有“prev”链接,因为我们正在查看第一页。“meta”下缺少“prev”字段以及“prev”链接的“templateRequired”值意味着该链接不能与该特定实例一起使用。

[CREF8]目前尚不清楚分页应如何与单个“thing”模式中的“collection”链接中的链接一起使用。从技术上讲,从项目到分页或过滤集合的链接应指向包含项目(在本例中为“thing”)的页面/过滤器,该项目是链接上下文。有关更多讨论,请参阅 GitHub 问题 #421。

让我们在入口点模式 (第 9.1 节) 中添加一个指向该集合的链接,其中包括分页输入,以便允许客户端应用程序直接跳转到特定页面。回想一下,入口点模式仅包含链接,因此我们只显示新添加的链接

{
    "rel": "tag:rel.example.com,2017:thing-collection",
    "href": "/things{?offset,limit}",
    "hrefSchema": {
        "$ref": "thing-collection#/definitions/pagination"
    },
    "submissionSchema": {
        "$ref": "thing#"
    },
    "targetSchema": {
        "$ref": "thing-collection#"
    }
}
                        

现在我们看到分页参数被接受为输入,因此我们可以跳转到集合中的任何页面。链接关系类型是一个自定义类型,因为通用“collection”链接只能与项目作为其上下文一起使用,而不能与入口点或其他资源一起使用。

9.5.2. 创建第一个项目

当我们没有任何“thing”时,我们也没有任何具有相关“collection”链接的资源。因此,我们无法使用“collection”链接的提交关键字来创建第一个“thing”;超模式必须针对实例进行评估。由于集合实例中的“elements”数组将为空,因此它也无法为我们提供集合链接。

但是,我们的入口点链接可以将我们带到空集合,我们可以使用超模式中“item”链接的存在来识别它是一个集合。由于“item”链接的上下文是集合,我们只需查找具有相同上下文的“self”链接,然后将其视为用于创建操作的集合。

据推测,我们入口点模式中的自定义链接关系类型足以确保我们找到了正确的集合。识别该自定义链接关系类型的客户端应用程序可能知道它可以立即假设目标是集合,但通用用户代理无法做到这一点。尽管在我们的示例中存在“-collection”后缀,但通用用户代理无法知道该子字符串是否表示超媒体资源集合,还是其他类型的集合。

一旦我们识别出“self”链接属于正确的集合,我们就可以使用其“submissionSchema”和/或“submissionMediaType”关键字来执行项目创建操作。 [CREF9]如果集合未过滤且未分页,这将完美运行。但是,通常应将 POST 请求发送到包含创建资源的集合,并且“self”链接必须包含任何过滤器、分页或其他查询参数。即使生成的项目与过滤器不匹配或未出现在该页面中,将 POST 请求发送到这样的“self”链接是否仍然有效?有关进一步讨论,请参阅 GitHub 问题 #421。 [CREF10]Hyper-Schema 的草案-04 定义了一个“create”链接关系,该关系以模式而不是实例作为其上下文。这与基于实例的链接模型不符,并且错误地使用操作名称作为链接关系类型。但是,定义一个更正确设计的从模式到集合实例的链接可能是解决此问题的可能方法之一。同样,有关更多详细信息,请参阅 GitHub 问题 #421。

10. 安全注意事项

JSON Hyper-Schema 定义了 JSON Schema 核心词汇,并且涉及到那里列出的所有安全注意事项。作为一种链接序列化格式,RFC 8288 Web 链接 [RFC8288] 的安全注意事项也适用,并进行了适当调整(例如,将“anchor”作为 LDO 关键字而不是 HTTP 链接标头属性)。

10.1. 目标属性

第 6.5 节 中所述,所有描述目标资源的 LDO 关键字都是建议性的,并且不得用于替代目标资源在响应操作时提供的权威信息。目标资源响应应指示其自己的超模式,该超模式是权威性的。

如果目标响应中的超模式与当前 LDO 中找到的超模式(按“$id”)匹配,则目标属性可以被认为是权威性的。 [CREF11]需要添加一些关于“$id”欺骗风险的内容,但鉴于规范的其他部分不鼓励始终重新下载链接的模式,因此风险缓解选项尚不清楚。

用户代理或客户端应用程序不得使用“targetSchema”的值来帮助解释在遵循链接后接收到的数据,因为这会使“安全”数据容易受到重新解释的影响。

在选择如何解释数据时,服务器提供的类型信息(或从文件名或任何其他常用方法推断出)必须是唯一考虑因素,并且不得使用链接的“targetMediaType”属性。用户代理可以使用此信息来确定如何表示链接或在何处显示链接(例如,悬停文本、在新标签页中打开)。如果用户代理决定将链接传递给外部程序,他们应该首先验证数据是否属于通常传递给该外部程序的类型。

这样做是为了防止“安全”数据的重新解释,类似于对“targetSchema”的预防措施。

在“targetHints”中传达的协议元数据值不得被视为权威性的。基于对元数据值的错误假设而适用的任何协议定义的安全注意事项都适用。

即使没有直接适用的协议安全注意事项,实现也必须准备好处理与链接的“targetHints”值不匹配的响应。

10.2. “self”链接

当“self”链接关系用于表示对象的完整表示时,如果目标 URI 不等效于或不是包含具有“self”链接的目标 URI 的资源表示请求使用的 URI 的子路径,则用户代理不应将该表示视为目标 URI 所表示的资源的权威表示。 [CREF12]目前尚不清楚本段中“子路径”选项的真正意图。它可能旨在允许集合中嵌入式项目表示的“self”链接(其目标 URI 通常是该集合 URI 的子路径)被视为权威性的。但是,这只是一个常见的設計慣例,似乎并没有基于 RFC 3986 或任何其他关于 URI 使用的指导。有关进一步讨论,请参阅 GitHub 问题 #485。

11. 致谢

感谢 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 和 Denis Laxalde 对该文档所做的提交和补丁。

12. 参考文献

12.1. 规范性引用

[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 月。
[RFC4287] Nottingham, M.R. Sayre,“Atom 联合格式”,RFC 4287,DOI 10.17487/RFC4287,2005 年 12 月。
[RFC6570] Gregorio, J.Fielding, R.Hadley, M.Nottingham, M.D. Orchard,“URI 模板”,RFC 6570,DOI 10.17487/RFC6570,2012 年 3 月。
[RFC6573] Amundsen, M.,“项目和集合链接关系”,RFC 6573,DOI 10.17487/RFC6573,2012 年 4 月。
[RFC6901] Bryan, P.Zyp, K.M. Nottingham,“JavaScript 对象表示法 (JSON) 指针”,RFC 6901,DOI 10.17487/RFC6901,2013 年 4 月。
[RFC8288] Nottingham, M.,“Web 链接”,RFC 8288,DOI 10.17487/RFC8288,2017 年 10 月。
[relative-json-pointer] Luff, G.H. Andrews,“相对 JSON 指针”,Internet 草案 draft-handrews-relative-json-pointer-00,2017 年 11 月。
[json-schema] Wright, A.H. Andrews,“JSON Schema:描述 JSON 文档的媒体类型”,Internet 草案 draft-handrews-json-schema-00,2017 年 11 月。
[json-schema-validation] Wright, A.Andrews, H.G. Luff,“JSON Schema 验证:用于 JSON 结构验证的词汇”,Internet 草案 draft-handrews-json-schema-validation-00,2017 年 11 月。

12.2. 信息性引用

[RFC2046] Freed, N.N. Borenstein,“多用途互联网邮件扩展 (MIME) 第二部分:媒体类型”,RFC 2046,DOI 10.17487/RFC2046,1996 年 11 月。
[RFC4151] Kindberg, T.S. Hawke,“'tag' URI 方案”,RFC 4151,DOI 10.17487/RFC4151,2005 年 10 月。
[RFC5789] Dusseault, L.J. Snell,“HTTP 的 PATCH 方法”,RFC 5789,DOI 10.17487/RFC5789,2010 年 3 月。
[RFC6068] Duerst, M., Masinter, L.J. Zawinski,"'mailto' URI 方案",RFC 6068,DOI 10.17487/RFC6068,2010 年 10 月。
[RFC7230] Fielding, R.J. Reschke,"超文本传输协议 (HTTP/1.1):消息语法和路由",RFC 7230,DOI 10.17487/RFC7230,2014 年 6 月。
[RFC7231] Fielding, R.J. Reschke,"超文本传输协议 (HTTP/1.1):语义和内容",RFC 7231,DOI 10.17487/RFC7231,2014 年 6 月。
[RFC7807] Nottingham, M.E. Wilde,"HTTP API 的问题详细信息",RFC 7807,DOI 10.17487/RFC7807,2016 年 3 月。
[I-D.reschke-http-jfv] Reschke, J.,"HTTP 头字段值的 JSON 编码",互联网草案 draft-reschke-http-jfv-06,2017 年 6 月。

附录 A. 在 API 中使用 JSON 超级模式

遵循 REST 架构风格约束的超媒体 API 能够创建通用的用户代理。这种用户代理没有特定于应用程序的知识。相反,它理解预定义的媒体类型、URI 方案、协议和链接关系,通常是通过识别这些关系并协调使用实现对其支持的现有软件来实现的。然后,客户端应用程序可以在此类用户代理的基础上构建,专注于自己的语义和逻辑,而不是交互的机制。

超级模式一次只关注一个资源和一组关联的链接。正如 Web 浏览器一次只处理一个 HTML 页面,没有关于该页面作为“站点”的一部分如何工作或是否工作的概念一样,支持超级模式的用户代理一次处理一个资源,没有任何关于该资源如何适应 API 或是否适应 API 的概念。

因此,超级模式适合在 API 中使用,但不适合描述 API 本身作为完整的实体。没有办法描述 API 范围内的概念,而不是资源和链接范围内的概念,并且此类描述超出了 JSON 超级模式的范围。

A.1. 使用超级模式进行资源演变

由于给定的 JSON 超级模式在单个时间点与单个资源一起使用,因此它本身没有版本控制的概念。但是,给定资源可以随着时间的推移更改其使用的模式或模式,并且这些模式的 URI 可以用于指示版本信息。当与支持使用媒体类型参数指示模式的媒体类型一起使用时,这些版本化的模式 URI 可用于内容协商。

资源可以表明它是多个模式的实例,这允许同时支持多个兼容版本。然后,客户端应用程序可以使用其识别的超级模式,并忽略较新或较旧的版本。

A.2. 响应和错误

由于超级模式一次表示一个资源,因此它不提供对使用链接执行的协议操作的所有可能响应的枚举。每个响应(包括错误)都被视为它自己的(可能是匿名的)资源,并且应该标识它自己的超级模式,并可选地使用合适的媒体类型,例如 RFC 7807 的“application/problem+json” [RFC7807],以允许用户代理或客户端应用程序解释在协议自身的状况报告之外提供的任何信息。

A.3. API 超级模式的静态分析

可以在没有实例数据的情况下静态分析一组超级模式以生成输出,例如文档或代码。但是,如果没有运行时实例数据,则无法访问验证和超级模式的全部功能集。

这是一个有意设计的选择,目的是为超媒体系统提供最大的运行时灵活性。JSON 模式作为一种媒体类型允许为静态分析和内容生成建立额外的词汇表,这些词汇表在本规范中没有涉及。此外,如果设计时描述是目标,则各个系统可以将使用限制在可以静态分析的子集上。 [CREF13]API 文档和其他目的的词汇表已被提议,欢迎在 https://github.com/json-schema-org/json-schema-vocabularies 贡献。

附录 B. 更改日志

[CREF14]此部分将在离开互联网草案状态之前删除。

draft-handrews-json-schema-hyperschema-00

draft-wright-json-schema-hyperschema-01

draft-wright-json-schema-hyperschema-00

draft-luff-json-hyper-schema-01

作者地址

Henry Andrews (编辑) Cloudflare, Inc. 旧金山, 加利福尼亚州 美国 电子邮件: [email protected]
Austin Wright (编辑) 电子邮件: [email protected]