網際網路工程任務組 H. Andrews, Ed.
網際網路草案 Cloudflare, Inc.
預定狀態:資訊性 A. Wright, Ed.
截止日期:2018 年 7 月 23 日 2018 年 1 月 19 日

JSON 超級綱要:JSON 超媒體註解的詞彙
draft-handrews-json-schema-hyperschema-01

摘要

JSON 綱要是一種基於 JSON 的格式,用於使用各種詞彙描述 JSON 資料。本文件指定了一個詞彙,用於使用超連結註解 JSON 文件。這些超連結包括描述如何透過超媒體環境(例如 HTTP)操作和與遠端資源互動的屬性,以及根據實例值判斷連結是否可用的屬性。本文件中描述的超連結序列化格式也可以獨立於 JSON 綱要使用。

讀者須知

此草案的問題列表可在<https://github.com/json-schema-org/json-schema-spec/issues>找到。

如需其他資訊,請參閱<https://json-schema.dev.org.tw/>

如要提供意見回饋,請使用此問題追蹤器、首頁上列出的溝通方式,或寄電子郵件給文件編輯人員。

本備忘錄的狀態

本網際網路草案的提交完全符合 BCP 78 和 BCP 79 的規定。

網際網路草案是網際網路工程任務組 (IETF) 的工作文件。請注意,其他群組也可能將工作文件散佈為網際網路草案。目前網際網路草案的清單位於 http://datatracker.ietf.org/drafts/current/。

網際網路草案是有效期最長為六個月的草案文件,隨時可能被其他文件更新、取代或廢棄。將網際網路草案當作參考資料或將其引用為「工作進行中」以外的內容是不恰當的。

本網際網路草案將於 2018 年 7 月 23 日到期。

著作權聲明

著作權 (c) 2018 IETF Trust 和被認定為文件作者的人員。保留所有權利。

本文件受 BCP 78 和 IETF Trust 與 IETF 文件相關的法律條款 (http://trustee.ietf.org/license-info) 的約束,這些條款在本文件發布之日生效。請仔細閱讀這些文件,因為它們描述了您在本文件方面的權利和限制。從本文件中擷取的程式碼元件必須包含「簡化版 BSD 授權」文字,如「信任法律條款」第 4.e 節所述,且不提供「簡化版 BSD 授權」中所述的擔保。


目錄

1. 簡介

JSON 超級綱要是一種 JSON 綱要詞彙,用於使用超連結和透過超媒體環境(例如 HTTP)處理和操作遠端 JSON 資源的指示註解 JSON 文件。

術語「JSON 超級綱要」用於指使用這些關鍵字的 JSON 綱要。術語「超級綱要」本身是指本規格範圍內的 JSON 超級綱要。

引入用於指定連結的主要機制是連結描述物件 (LDO),它是 RFC 8288 第 2 節 [RFC8288]中定義的抽象連結模型的序列化。

本規格將使用 JSON 綱要核心 [json-schema]JSON 綱要驗證 [json-schema-validation] 規格定義的概念、語法和術語。建議讀者手邊備有這些規格。

2. 符號慣例

本文件中「必須 (MUST)」、「不得 (MUST NOT)」、「必要 (REQUIRED)」、「應 (SHALL)」、「不應 (SHALL NOT)」、「應該 (SHOULD)」、「不應該 (SHOULD NOT)」、「建議 (RECOMMENDED)」、「可 (MAY)」和「可選 (OPTIONAL)」等關鍵字應按照 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 Hyper-Schema 實作能夠接收一個超連結綱要、一個實例,在某些情況下還會接收客戶端輸入,並產生一組完全解析的有效連結。根據 RFC 8288,第 2 節 [RFC8288] 的定義,連結包含一個上下文、一個具類型的關聯、一個目標,以及可選的額外目標屬性。

關聯類型和目標屬性直接取自每個連結的連結描述物件。上下文和目標識別符號則是透過 URI 範本、實例資料,以及(在目標識別符號的情況下)客戶端輸入的某種組合來建構。

目標總是透過 URI 完全識別。由於 application/json 和許多其他可用於 JSON Hyper-Schema 的媒體類型缺乏 URI 片段識別符號語法,上下文可能僅透過 URI 部分識別。在這種情況下,剩餘的識別將會以 JSON 指標提供。

一些 IANA 註冊的連結關聯類型在 JSON Hyper-Schema 文件中具有特定的語意。「self」連結用於與實例文件所代表的資源互動,而「collection」和「item」連結則識別可以假設具有集合特定語意的資源。

4. 元綱要和輸出綱要

JSON Hyper-Schema 元綱要目前的 URI 是 <https://json-schema.dev.org.tw/draft-07/hyper-schema#>

連結描述格式 [ldo] 可以不使用 JSON Schema,而且可以透過將規範的連結描述綱要作為使用連結的資料結構的綱要來宣告此格式的使用。規範連結描述綱要的 URI 為:<https://json-schema.dev.org.tw/draft-07/links#>

JSON Hyper-Schema 實作可以自由地以任何格式提供輸出。然而,為了在符合性測試套件中使用,定義了特定的格式,該格式也用於說明 「實作要求」 [implementation] 中的重點,並顯示 範例 [examples] 產生的輸出。建議實作應能夠以這種格式產生輸出,以利於測試。描述建議輸出格式的 JSON Schema 的 URI 是 <https://json-schema.dev.org.tw/draft-07/hyper-schema-output#>

5. 綱要關鍵字

根據 JSON Schema 驗證的第 3 節 [json-schema-validation] 的定義,適用於實例中某個位置的所有綱要中的超連結綱要關鍵字都可以與該實例一起使用。

當多個子綱要適用於給定的子實例時,所有「link」陣列都必須以任何順序合併為單一集合。結果集合中的每個物件都必須保留其各自的適用「base」值清單,這些值來自同一綱要和任何父綱要,並按解析順序排列。

與所有 JSON Schema 關鍵字一樣,本節中描述的所有關鍵字都是可選的。最小的有效 JSON Hyper-Schema 是空白物件。

5.1. base

如果存在此關鍵字,則必須先解析為 URI 範本 [uriTemplating],然後必須根據實例的目前 URI 基底解析為 URI 參考。在處理包含「base」的子綱要及其中的所有子綱要時,結果必須設定為實例的新 URI 基底。

當為了與「anchor」一起使用而解析「base」範本時,其解析過程可能與為了與「href」一起使用而解析時不同,這在 URI 範本化章節中會詳細說明。

5.2. links

綱要的「links」屬性用於將連結描述物件與實例關聯。此屬性的值必須是一個陣列,且陣列中的項目必須是連結描述物件,如下所述。

6. 連結描述物件

連結描述物件 (LDO) 是 RFC 8288,第 2 節 [RFC8288] 中定義的抽象連結模型的序列化。如該文件中所述,連結包含一個上下文、一個關聯類型、一個目標,以及可選的目標屬性。JSON Hyper-Schema 的 LDO 提供所有這些內容,以及額外的功能,可使用 JSON Schema 以各種方式描述與連結一起使用的輸入。

由於使用 URI 範本來識別連結上下文和目標,以及在識別目標時可選地進一步使用客戶端輸入,因此 LDO 是一個連結範本,當與 JSON 實例文件一起使用時,可能會解析為多個連結。

LDO 的特定用途,通常涉及跨協定的請求和回應,被稱為操作。對於許多協定,任何給定的連結都可能有多個操作。協定由目標的 URI 方案表示。請注意,並非所有 URI 方案都表示可以用於通訊的協定,即使具有表示此類協定的 URI 方案的資源也不一定可以透過該協定使用。

連結描述物件必須是一個物件,並且必須存在 「href」 [href]「rel」 [rel] 屬性。本節將簡要介紹每個關鍵字,並在文件的後續部分提供額外的使用說明和全面的範例。

6.1. 連結上下文

在 JSON Hyper-Schema 中,連結的上下文資源預設為其附加的子實例(如 JSON Schema 驗證規格的第 3 節 [json-schema-validation] 所定義)。這通常不是整個實例文件。可以使用本節中的關鍵字來變更此預設上下文。

根據實例的媒體類型,可能可以,也可能無法將 URI 指派給確切的預設上下文資源。特別是,application/json 沒有定義 URI 片段解析語法,因此無法透過 URI 完全識別一般 JSON 文件中的屬性或陣列元素。當無法產生完整的 URI 時,上下文的位置應透過實例文件的 URI,以及一個獨立的純文字 JSON 指標來傳達。

實作必須能夠建構連結上下文的 URI,以及(如果需要完整識別),一個符合 RFC 6901,第 5 節 [RFC6901] 的純文字 JSON 指標字串表示形式,來取代 URI 片段。根據 URI 範本建構 URI 的過程在 URI 範本化 [uriTemplating] 章節中給出。

6.1.1. anchor

此屬性設定連結的上下文 URI。此屬性的值是 URI 範本 [RFC6570],並且產生的 URI 參考 [RFC3986] 必須根據實例的基底 URI 來解析。

URI 是使用與 「href」 [href] 屬性所述相同的過程,從提供的 URI 範本計算得出的,但 「hrefSchema」 [hrefSchema] 必須不適用。與目標 URI 不同,上下文 URI 不接受使用者輸入。

6.1.2. anchorPointer

此屬性變更實例中被視為連結上下文資源的點。此屬性的值必須是 JSON 字串表示形式的有效 JSON 指標,或是一個根據預設上下文評估的有效 相對 JSON 指標 [relative-json-pointer]

雖然使用 「anchor」 [anchor] 關鍵字最好設定具有已知 URI 的替代上下文,但由於 application/json 缺少片段識別符號語法,因此通常無法使用 URI 變更 JSON 實例中的上下文。

即使在將 JSON 指標定義為片段識別符號語法的「+json」媒體類型中,如果預設上下文巢狀在陣列中,也無法取得預設上下文在該陣列中的位置索引,以建構指向同一巢狀 JSON 物件中另一個屬性的指標。這將在範例中展示。

如果實例的媒體類型允許此類片段,則處理此關鍵字的結果應為 URI 片段。否則,它必須是字串編碼的 JSON 指標。

6.2. 連結關聯類型

連結的關聯類型識別其語意。它是傳達應用程式如何與資源互動的主要方式。

關係定義通常不依賴於媒體類型,建議使用者利用最合適的現有已接受的關係定義。

6.2.1. rel

此屬性的值必須是一個字串,而且必須是 RFC 8288,第 2.1 節中定義的單一連結關聯類型。

此屬性為必填項。

6.2.2. 「self」連結

「self」連結,如 RFC 4287 的第 4.2.7.2 節 [RFC4287] 最初定義的,表示目標 URI 識別的資源與連結上下文等效。在 JSON Hyper-Schema 中,「self」連結必須可以從實例解析,因此不得出現「hrefSchema」。

超連結綱要作者應使用「templateRequired」來確保「self」連結具有所有使用所需的實例資料。

超連結綱要實作必須識別關聯類型為「self」且將整個目前實例文件作為其上下文的連結,描述使用者代理程式如何與該實例文件所代表的資源互動。

6.2.3. "collection" 與 "item" 連結

RFC 6573 [RFC6573] 定義並註冊了 "item" 和 "collection" 連結關係類型。JSON Hyper-Schema 對這些類型所指示的集合資源施加了額外的語意。

實作必須將 "collection" 連結的目標和 "item" 連結的上下文視為集合。

超媒體中一個眾所周知的設計模式是使用集合資源來建立集合的成員,並為其提供伺服器指定的 URI。如果 URI 方案所指示的協定定義了適用於建立具有伺服器指定 URI 的資源的特定方法,則由這些連結關係類型識別的集合資源,不得為該方法定義與建立集合成員的語意相衝突的語意。集合資源可以透過此類協定方法實作項目建立,並且使用者代理可以假設任何此類操作(如果存在)都具有項目建立語意。

由於此方法將對應於 JSON Hyper-Schema 的資料提交概念,因此連結的 "submissionSchema" [submissionSchema] 欄位應該與集合項目的表示形式的綱要相容,如 "item" 連結的目標資源或 "collection" 連結上下文資源的 "self" 連結所指示。

6.2.4. 使用擴充關係類型

當沒有已註冊的關係(除了 "related")適用時,鼓勵使用者建立自己的擴充關係類型,如 RFC 8288 的 2.1.2 節 [RFC8288] 中所述。選擇連結關係類型 URI 最簡單的方法是使用已經用於識別系統主要資源的 URI 方案,或是使用人類可讀的、不可取值的 URI 方案,例如 RFC 4151 定義的 "tag" [RFC4151]

擴充關係類型 URI 不需要可取值,即使在使用允許這樣做的方案時也是如此。

6.3. 連結目標

目標 URI 範本用於識別連結的目標,可能會使用實例資料。此外,透過 "hrefSchema" [hrefSchema],此範本可以根據用戶端輸入識別一組可能使用的目標資源。解析 URI 範本的完整過程,無論是否有用戶端輸入,都包含在 URI 範本 [uriTemplating] 區段中。

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" 屬性。使用者代理可以使用此資訊,在連結被追蹤之前通知他們向使用者呈現的介面,但不得在解釋結果資料時使用此資訊。相反地,使用者代理必須使用回應給定的媒體類型進行執行階段解釋。請參閱 "安全注意事項" [security] 區段,以詳細檢視 "targetMediaType" 的濫用。

對於支援內容協商的協定,實作可以選擇使用 "headerSchema" [headerSchema] 中的協定特定資訊來描述可能的目標媒體類型。如果同時存在協定特定資訊和 "targetMediaType",則 "targetMediaType" 的值必須與協定特定資訊相容,並且應指示在沒有內容協商的情況下將傳回的媒體類型。

當沒有此類協定特定資訊可用時,或當實作無法識別所涉及的協定時,則應將該值視為 "application/json"。

6.5.4. targetSchema

此屬性提供了一個綱要,預期用於描述連結目標的表示形式。根據協定,綱要可能會或可能不會描述使用連結執行的任何特定操作的請求或回應。請參閱 JSON Hyper-Schema 和 HTTP [HTTP] 區段,以深入討論如何將此關鍵字用於 HTTP。

6.5.5. targetHints

[CREF1]本節嘗試透過將其大部分結構延遲到 URI 方案所指示的協定,來在全面性和彈性之間取得平衡。請注意,資源可以使用可取值的方案透過 URI 識別,但無法透過該協定存取。雖然目前非常鬆散,但預計本節將根據草案回饋變得更加明確,並且在未來的草案中可能會發生重大變化。

此屬性的值僅供參考。它表示預期透過與目標資源互動而發現的資訊,通常以協定特定控制資訊或元資料的形式,例如回應 HTTP HEAD 或 OPTIONS 請求時傳回的標頭。協定由 "href" URI 方案確定,但請注意,不保證資源可以透過此類協定存取。

此屬性的值應為物件。此物件的鍵應為控制資料欄位名稱的小寫形式。每個值都應為陣列,以便統一處理多值欄位。多個值必須以陣列形式呈現,而不是單一字串。

控制資訊不適合以 JSON 物件表示的協定,可以使用其他資料類型(例如陣列)表示。

無法理解為所指示協定一部分的值必須由 JSON Hyper-Schema 實作忽略。應用程式可以使用這些值,但不得假設與其他實作的互通性。

實作不得假設此物件中說明了所有可發現的資訊。用戶端應用程式必須正確處理與此屬性值衝突的執行階段回應。

用戶端應用程式不得假設實作會根據此屬性的值自動採取任何動作。

請參閱 "JSON Hyper-Schema 和 HTTP" [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

[CREF2]與 "targetHints" 類似,這個關鍵字在規格上有些不明確,目的是鼓勵實驗和回饋,以便在彈性和清晰度之間取得平衡。

如果存在,此屬性是特定協定請求標頭或類似的控制和元數據的綱要。此物件的值必須是有效的 JSON 綱要。協定由 "href" URI 方案決定,但請注意,不保證可以透過此協定存取資源。綱要僅供參考;目標資源的行為不受其存在所約束。

此關鍵字的目的在於宣傳目標資源的互動功能,並向使用者代理程式和客戶端應用程式指示哪些標頭和標頭值可能有用。使用者代理程式和客戶端應用程式可以使用綱要來驗證相關標頭,但不得假設缺少標頭或值是禁止使用的。雖然綱要作者可以將 "additionalProperties" 設定為 false,但不建議這樣做,且不得阻止客戶端應用程式或使用者代理程式在發出請求時提供額外的標頭。

JSON 資料模型到標頭的確切映射與協定相關。但是,在大多數情況下,此綱要應指定 "object" 類型,且屬性名稱應為控制資料欄位名稱的小寫形式。請參閱 「JSON 超綱要和 HTTP」 [HTTP] 章節,以取得關於將此關鍵字與 HTTP 和類似協定搭配使用的詳細指導。

"headerSchema" 適用於協定支援的任何請求方法或命令。當產生請求時,使用者代理程式和客戶端應用程式應忽略與該請求無關的標頭綱要。

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。[CREF3]此陳述可能會移至範例的結尾處。

6.6.4.2. submissionSchema

此屬性包含一個綱要,該綱要定義了根據 "submissionMediaType" 屬性編碼並傳送到目標資源進行處理的文件的可接受結構。這可以被視為描述目標資源實作的處理函數的網域。

這是一個與 "targetSchema" [targetSchema] 屬性不同的概念,後者描述了目標資訊資源(包括在 PUT 請求中取代資源的內容),而 "submissionSchema" 描述了要由資源評估的使用者提交的請求資料。"submissionSchema" 旨在用於具有有效負載的請求,這些有效負載不一定根據目標表示來定義。

省略 "submissionSchema" 的行為與值為 "true" 的行為相同。

7. 實作要求

在高層次上,符合規範的實作將滿足以下要求。這些要求中的每一個都將在個別關鍵字章節和關鍵字群組概觀中進行更詳細的介紹。

請注意,關於實作如何必須識別 "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 相關聯。

實作必須支援按其附件指標或內容指標查詢連結,可以通過執行查詢或提供具有兩個指標確定的所有連結的集合來實現,以便使用者代理程式可以自行實作查詢。

當按內容指標執行查詢時,必須按照附加的陣列元素的相同順序返回附加到同一陣列元素的連結。

7.2. URI 範本化

三個超綱要關鍵字是 URI 範本 [RFC6570]:"base"、"anchor" 和 "href"。每個關鍵字都單獨解析為 URI 參考,然後將 anchor 或 href URI 參考相對於 base 進行解析(base 本身會根據需要相對於較早的 base 進行解析,每個 base 都首先從 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. 接受輸入(呈現網頁表單、進行回呼等)
  4. 驗證輸入資料集(不是範本解析資料集)
  5. 將輸入放入範本解析資料集中,覆寫任何現有值

「InputForm」代表任何適當的輸入機制。這可能是一個實際的網頁表單,或者是一個更程式化的結構,例如接受特定欄位和資料類型,並帶有給定初始值(如果有的話)的回呼函式。

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),因此應使用任何合理的表示方式。Schema 和 API 作者應牢記這一點,如果確切的表示很重要,則使用其他類型(例如字串或布林值)。如果數字是以字串形式作為輸入提供,則應使用作為輸入的字串。

7.3. 提供對 LDO 關鍵字的存取

對於給定的連結,實作必須使所有目標屬性關鍵字的值直接提供給使用者代理程式。實作可以提供額外的介面來使用此資訊,如每個關鍵字的章節中所討論。

對於給定的連結,實作必須使每個輸入 schema 關鍵字的值直接提供給使用者代理程式。

為了鼓勵 URI 範本解析過程的封裝,實作可以省略僅用於建構 URI 的 LDO 關鍵字。但是,實作必須提供對連結關係類型的存取權。

無法識別的關鍵字應提供給使用者代理程式,並且必須忽略其他部分。

7.4. 請求

hyper-schema 實作應該提供建構對目標資源的任何有效請求所需的所有資訊。

LDO 可以表達執行連結上任何操作所需的所有資訊。本節說明使用者代理程式應檢查哪些 hyper-schema 欄位,以從任何實例資料和用戶端輸入的組合中建構請求。hyper-schema 實作本身不應建構和傳送請求。

目標 URI 建構規則,包括用於接受輸入的「hrefSchema」,對於所有可能的請求都是相同的。

不帶有主體 payload 的請求不需要額外的關鍵字支援。

將目標表示形式作為 payload 的請求應使用「targetSchema」和「targetMediaType」關鍵字進行輸入描述和 payload 驗證。如果協定允許以基於媒體類型修改的表示形式為基礎的 payload 進行操作(例如修補媒體類型),則應以協定特定的方式透過「targetHints」指示此媒體類型。

將 payload 不從目標資源的表示形式衍生出來的請求,應使用「submissionSchema」和「submissionMediaType」關鍵字進行輸入描述和 payload 驗證。超媒體中使用的協定通常每個連結僅支援一個此類非表示形式操作。

透過單個超媒體協定操作,將具有任意不同請求結構的多個應用程式操作管道化的 RPC 系統,不在 JSON Hyper-Schema 等超媒體格式的範圍內。

7.5. 回應

作為超媒體格式,JSON Hyper-Schema 關注於描述資源,包括足夠詳細地描述其連結以建立所有有效請求。它不關注直接描述這些請求的所有可能回應。

與任何超媒體系統一樣,回應應為自我描述的。在 hyper-schema 的上下文中,這表示每個回應都必須連結到自己的 hyper-schema。雖然預期由目標資源的表示形式組成的回應會根據「targetSchema」和「targetMediaType」進行驗證,但這些關鍵字僅為建議性質,如果與回應本身相矛盾,則必須忽略。

其他回應,包括錯誤回應、複雜的重定向和處理狀態表示形式,也應連結到自己的 schema 並使用適當的媒體類型(例如,「application/problem+json」[RFC7807]用於錯誤)。由於某些錯誤是由不了解 hyper-schema 的中介者產生,而不是由來源產生,因此某些錯誤可能不會連結到 schema。

預期使用者代理程式會充分了解協定狀態碼和回應媒體類型,以處理常見情況,並提供足夠的資訊給用戶端應用程式以處理特定領域的回應。

在設計時靜態對應所有可能的回應及其 schema 不在 JSON Hyper-Schema 的範圍內,但可能在其他以 hyper-schema 為基礎的 JSON Schema 詞彙的範圍內(請參閱 附錄 A.3)。

7.6. 串流剖析器

當與串流剖析器一起使用時,基於其上下文探索連結或使用連結上下文識別集合的要求,會帶來獨特的挑戰。在不處理整個 schema 和實例文件的情況下,不可能權威地滿足這些要求。

此類實作可能會選擇根據迄今為止處理的資料傳回非權威的答案。在提供此方法時,實作必須清楚說明回應的性質,並且必須提供一個選項來封鎖並等待直到處理完所有資料,並且可以傳回權威的答案。

8. JSON Hyper-Schema 和 HTTP

雖然 JSON Hyper-Schema 是一種超媒體格式,因此與協定無關,但預期其最常見的用途將是在 HTTP 系統中,或使用與 HTTP 明確類似的協定(例如 CoAP)的系統中。

本節提供有關如何將每個常見的 HTTP 方法與連結一起使用,以及集合資源如何對 HTTP POST 施加額外的限制的指南。此外,還提供了有關提示 HTTP 回應標頭值以及描述與給定資源相關的可能 HTTP 請求標頭的指南。

JSON Schema 核心規格的第 11 節[json-schema]提供了有關將超媒體系統中的實例連結到其 schema 的指南。可以使用可透過網路存取的 schema 來完成,也可以僅識別預先封裝在用戶端應用程式中的 schema。JSON Hyper-Schema 有意不約束此機制,儘管建議盡可能使用核心規格中概述的技術。

8.1. 每個目標和關係類型一個連結

連結描述物件不直接指示目標資源支援哪些操作(例如 HTTP 方法)。相反,操作應主要從連結關係類型[rel]和 URI 模式推斷。

這表示對於每個目標資源和連結關係類型對,schema 作者應僅定義單個 LDO。雖然可以使用帶有「targetHints」的「allow」來重複帶有標記為允許的不同 HTTP 方法的關係類型和目標對,但不建議這樣做,且符合規範的實作可能無法很好地支援。

使用每個 HTTP 方法所需的所有資訊都可以在單個 LDO 中傳達,如本節所述。「targetHints」中的「allow」欄位僅用於提示支援哪些操作,而不是單獨定義每個操作。

但是請注意,資源始終可以在執行階段拒絕操作,例如由於授權失敗,或由於控制操作可用性的其他應用程式狀態。

8.2. 「targetSchema」和 HTTP

「targetSchema」描述連結目標端的資源,而「targetMediaType」定義該資源的媒體類型。對於 HTTP 連結,也可以使用「headerSchema」來描述「Accept」請求標頭中使用的有效值,該標頭可以支援多個媒體類型或媒體範圍。當同時存在這兩種指示目標媒體類型的方式時,「targetMediaType」應指示預設的表示媒體類型,而「headerSchema」中「accept」的 schema 應包括預設值以及可以請求的任何其他媒體類型或媒體範圍。

由於許多 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」標頭傳達,該標頭可以包含在「targetHints」中。適用於 PATCH 的媒體類型定義了表達對文件變更的語法,該語法可以應用於「targetSchema」描述的表示形式,以確定語法上有效的請求 payload 集。通常,驗證 PATCH 請求的最簡單方法是套用它並驗證結果是否為正常表示形式。

8.3. HTTP POST 和「submission*」關鍵字

JSON Hyper-Schema 允許處理任意資料的資源,除了處理目標的表示形式之外或替代處理目標的表示形式。此任意資料由「submissionSchema」和「submissionMediaType」關鍵字描述。在 HTTP 的情況下,POST 方法是唯一處理此類資料的方法。雖然有一些關於將 POST 與集合一起使用的慣例,但 POST 請求的語義由目標資源定義,而不是由 HTTP 定義。

除了與協定無關的「submission*」關鍵字(有關非 HTTP 範例,請參閱第 9.3 節)之外,「Accept-Post」標頭可用於指定必要的媒體類型,並且可以透過「targetHints」欄位發佈。[CREF4]如果同時使用這兩者會發生什麼?此外,「submissionSchema」是必須支援的,而「targetHints」充其量只是應該支援的。但是禁止在「targetHints」中使用「Accept-Post」似乎不正確。

除了設定「Content-Location」的 201 或 200 之外,POST 的成功回應也沒有 HTTP 定義的語義。與所有 HTTP 回應一樣,回應中的任何表示形式都應連結到自己的 hyper-schema,以指示如何處理它。如附錄 A.2所述,將超連結與所有可能的操作回應連結起來不在 JSON Hyper-Schema 的範圍內。

8.4. 使用「targetHints」最佳化 HTTP 可探索性

[CREF5]最好也加入一個包含 CoAP 範例的章節。

HTTP 回應標頭資訊的 JSON 序列化應該遵循正在進行中的「HTTP 標頭欄位值的 JSON 編碼」 [I-D.reschke-http-jfv]所建立的指南。該文件中範例所示的方法應盡可能應用於其他結構類似的標頭。

所有可能的 HTTP 方法回應的標頭都共用「headerSchema」。特別是,HEAD 回應中出現的標頭和 OPTIONS 回應中出現的標頭都可以出現。「headerSchema」中並未區分哪個方法回應包含哪個標頭。

建議綱要作者在適用的情況下,為以下類型的 HTTP 標頭的值提供提示

一般而言,在不同時間可能具有不同值的標頭不應包含在「targetHints」中。

8.5. 使用「headerSchema」宣告 HTTP 功能

綱要應該撰寫為描述遵循正在進行中的「HTTP 標頭欄位值的 JSON 編碼」 [I-D.reschke-http-jfv]所建立指南的 JSON 序列化。該文件中範例所示的方法應盡可能應用於其他結構類似的標頭。

建議綱要作者在適用的情況下,描述以下類型的 HTTP 標頭的可用用法

快取控制和條件請求標頭等標頭通常由中介實作,而不是由資源實作,因此通常不適用於描述。雖然資源必須提供使用條件請求所需資訊,但此類標頭和相關回應的執行時間處理並非特定於資源。

8.6. 透過集合建立資源

當使用 HTTP 或類似於 HTTP 的協定(例如 CoAP)時,這是透過將要建立的個別資源的表示法 POST 到集合資源來完成的。識別集合和項目資源的過程在第 6.2.3 節中說明。

8.7. 內容協商和綱要演進

JSON 超綱要促進了 HTTP 內容協商,並允許主動和被動策略的混合。如上所述,超綱要可以使用「headerSchema」關鍵字來包含諸如「Accept」、「Accept-Charset」、「Accept-Language」等 HTTP 標頭的綱要。使用者代理或客戶端應用程式可以使用此綱要中的資訊(例如支援語言的列舉清單),而不需發出初始請求來啟動被動協商過程。

如此一來,設定這些標頭的主動內容協商技術可以從伺服器關於可能值的資訊中得知,類似於檢查被動協商中的替代方案清單。

對於允許將綱要指定為媒體類型參數的媒體類型,在請求中傳送或在「headerSchema」中宣告的「Accept」值可以包括預期協商表示法所符合之綱要的 URI。內容協商中綱要參數的一個可能用途是,如果資源隨著時間推移符合多個不同的綱要版本。客戶端應用程式可以使用這種方式在「Accept」標頭中指示它理解的版本。

9. 範例

本節說明如何使用建構 URI 和 JSON 指標的關鍵字。結果以測試套件使用的格式顯示。[CREF6]需要發布並連結它,但對於現階段正在審查內容的您們來說,應該是不言自明的。

大多數其他關鍵字都是直接的(「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,並提供兩個連結:一個「about」連結到 API 文件,以及一個「self」連結,表示這是基本 URI 的綱要。在這種情況下,基本 URI 也是進入點 URI。

{
    "$id": "https://schema.example.com/entry",
    "$schema": "https://json-schema.dev.org.tw/draft-07/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.dev.org.tw/draft-07/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。但是,您可以將此綱要用於僅包含資料欄位的執行個體,這允許您驗證您即將建立的「thing」執行個體。

讓我們在進入點綱要中加入一個連結,讓您可以直接跳到特定的 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」,因此並非絕對必要。如果未將「id」標記為「hrefSchema」中的必需,則提供「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.dev.org.tw/draft-07/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": ""
}
                    

請注意取代「targetUri」的「href*」關鍵字。這些是三種可能的「targetUri」值,涵蓋不同種類的輸入。以下是每個範例

沒有額外的或已變更的輸入
"mailto:[email protected]?subject=The%20Awesome%20Thing"
將「title」變更為「your work」
"mailto:[email protected]?subject=your%20work"
變更 title 並新增「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 連結標頭中,您可以將「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」連結具有與「rel=self」連結相同的目標 URI,並將「anchor」(識別連結的內容)設定為子項的 URI。當「self」連結也存在時,此類反向連結很容易被工具偵測到。

以下超綱要,應用於上述回應中的執行個體,將產生相同的「self」連結和帶有「anchor」的「up」連結。它也顯示了範本化「base」URI 的使用,以及「templatePointers」中絕對和相對 JSON 指標的使用。

{
    "$id": "https://schema.example.com/tree-node",
    "$schema": "https://json-schema.dev.org.tw/draft-07/hyper-schema#",
    "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}"
        }
    ]
}
                    

「base」範本對目標(「href」)和內容(「anchor」)URI 的評估方式相同。

請注意使用的兩種不同類型的 templatePointers。「thisNodeId」會映射到一個絕對 JSON 指標「/id」,而「childId」會映射到一個相對指標「0」,這表示目前項目的值。絕對 JSON 指標不支援任何形式的萬用字元,因此沒有辦法在不使用相對 JSON 指標的情況下指定像「目前項目」這樣的概念。

9.5. 集合

在許多系統中,個別資源會被分組為集合。這些集合通常也提供一種方式來建立具有伺服器指派識別符的個別項目資源。

在此範例中,我們將重複使用先前章節中顯示的個別事物綱要。為了方便起見,此處重複顯示,並新增了一個「collection」連結,其「targetSchema」參考指向我們接下來將介紹的集合綱要。

{
    "$id": "https://schema.example.com/thing",
    "$schema": "https://json-schema.dev.org.tw/draft-07/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.dev.org.tw/draft-07/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"
    }
]

                    

在所有情況下,都會顯示媒體類型 application/json 的實例的內容 URI,該媒體類型不支援片段。如果實例媒體類型是 application/instance+json,支援 JSON 指標片段,則內容 URI 將包含與內容指標欄位相同的片段。對於不包含片段的 application/json 和其他媒體類型,務必同時考慮內容指標和內容 URI。

有三個「self」連結,一個用於集合,另一個用於「elements」陣列中的每個項目。項目「self」連結定義在個別「thing」綱要中,該綱要以「$ref」參考。這三個連結可以透過其內容或附加指標來區分。我們將在9.5.2 節中重新檢視集合「self」連結的「submissionSchema」。

有兩個「item」連結,一個用於「elements」陣列中的每個項目。與「self」連結不同,這些連結僅在集合綱要中定義。它們每個都具有與共享相同附加指標的相應「self」連結相同的目標 URI。但是,每個連結都有不同的內容指標。「self」連結的內容是「elements」中的項目,而「item」連結的內容始終是整個集合,無論特定項目為何。

最後,有兩個「collection」連結,一個用於「elements」中的每個項目。在個別項目綱要中,這些連結會產生以項目資源作為內容的連結。當從集合綱要參考時,內容是「elements」陣列中相關「thing」的位置,而不是該「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」值,表示此連結無法在此特定實例中使用。

[CREF7]目前尚不清楚分頁如何與個別「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」關鍵字來執行項目建立操作。[CREF8]如果集合未經過篩選且未分頁,則此操作完美有效。但是,一般應該 POST 到將包含所建立資源的集合,而「self」連結必須包含任何篩選器、分頁或其他查詢參數。即使產生的項目不符合篩選器或未出現在該頁面中,是否仍然可以 POST 到這樣的「self」連結?如需進一步討論,請參閱 GitHub 問題 #421。[CREF9]Hyper-Schema 的 Draft-04 定義了一個「create」連結關係,其內容是綱要而不是實例。這不符合基於實例的連結模型,並且錯誤地使用操作名稱作為連結關係類型。但是,定義從綱要到集合實例的設計更正確的連結可能是解決此問題的一種可能方法。同樣,如需更多詳細資訊,請參閱 GitHub 問題 #421。

10. 安全性考量

JSON 超綱要定義了 JSON 綱要核心的詞彙,並涉及此處列出的所有安全性考量。作為連結序列化格式,RFC 8288 Web 連結[RFC8288]的安全性考量也適用,並進行適當調整 (例如,「anchor」作為 LDO 關鍵字,而不是 HTTP 連結標頭屬性)。

10.1. 目標屬性

6.5 節所述,所有描述目標資源的 LDO 關鍵字都是建議性的,不得用於取代目標資源在回應操作時提供的權威資訊。目標資源回應應該指示其自己的超綱要,該綱要是權威的。

如果目標回應中的超綱要與找到目前 LDO 的超綱要相符 (依「$id」),則目標屬性可視為權威的。[CREF10]需要新增一些關於「$id」欺騙風險的內容,但考慮到規格的其他部分不鼓勵總是重新下載連結的綱要,因此風險緩解選項不明確。

使用者代理程式或用戶端應用程式不得使用「targetSchema」的值來協助解讀接收到響應連結後收到的資料,因為這會使「安全」資料容易被重新解讀。

在選擇如何解讀資料時,必須將伺服器提供的類型資訊 (或從檔案名稱推斷的類型資訊,或任何其他常用方法) 作為唯一考量,不得使用連結的「targetMediaType」屬性。使用者代理程式可以使用此資訊來判斷它們如何表示連結或在哪裡顯示連結 (例如,滑鼠停留文字、在新標籤中開啟)。如果使用者代理程式決定將連結傳遞到外部程式,則它們應該先驗證資料的類型是否通常會傳遞到該外部程式。

這是為了防止重新解讀「安全」資料,類似於「targetSchema」的預防措施。

在「targetHints」中傳達的通訊協定中繼資料值不得視為權威值。任何可能基於對中繼資料值的錯誤假設而適用的通訊協定所定義的安全性考量都適用。

即使沒有直接適用的通訊協定安全性考量,實作也必須準備好處理與連結的「targetHints」值不符的回應。

10.2. 「self」連結

當使用「self」的連結關係來表示物件的完整表示法時,如果目標 URI 不等於或不是用於請求包含具有「self」連結的目標 URI 的資源表示法的 URI 的子路徑,則使用者代理程式不應將表示法視為目標 URI 所表示資源的權威表示法。[CREF11]本段中「子路徑」選項的意圖已不再完全清楚。它可能是為了允許集合中嵌入的項目表示法的「self」連結,這些表示法通常具有作為該集合 URI 子路徑的目標 URI,被視為權威表示法。但是,這只是一種常見的設計慣例,並且似乎不是基於 RFC 3986 或任何其他關於 URI 用法的指南。如需進一步討論,請參閱 GitHub 問題 #485。

11. 致謝

感謝 Gary Court、Francis Galiegue、Kris Zyp 和 Geraint Luff 對 JSON 綱要初始草案的貢獻。

感謝 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 draft-handrews-relative-json-pointer-01, 2018 年 1 月。
[json-schema] Wright, A.H. Andrews, "JSON 綱要:用於描述 JSON 文件的一種媒體類型", Internet-Draft draft-handrews-json-schema-00, 2017 年 11 月。
[json-schema-validation] Wright, A., Andrews, H.G. Luff, "JSON 綱要驗證:用於 JSON 結構驗證的詞彙", Internet-Draft 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 編碼", Internet-Draft draft-reschke-http-jfv-06, 2017 年 6 月。

附錄 A. 在 API 中使用 JSON 超綱要

遵循 REST 架構樣式約束的超媒體 API 能夠建立通用使用者代理。此類使用者代理沒有特定於應用程式的知識。相反地,它透過識別並協調使用現有支援這些媒體類型的軟體,來理解預先定義的媒體類型、URI 方案、協定和連結關係。然後可以在此類使用者代理之上建立用戶端應用程式,專注於它們自己的語義和邏輯,而不是互動的機制。

超綱要一次僅關注一個資源和一組相關連結。正如網頁瀏覽器一次只處理一個 HTML 頁面,而沒有概念該頁面是否或如何作為「網站」的一部分運作一樣,具有超綱要意識的使用者代理一次只處理一個資源,而沒有任何概念該資源是否或如何適合 API。

因此,超綱要適用於在 API 中使用,但不適用於將 API 描述為完整的獨立實體。沒有辦法描述 API 範圍的概念,而不是資源和連結範圍的概念,而此類描述超出了 JSON 超綱要的邊界。

A.1. 使用超綱要進行資源演進

由於給定的 JSON 超綱要在單一時間點與單一資源一起使用,因此它沒有固有的版本控制概念。然而,給定資源可以隨著時間的推移而更改它使用的綱要或綱要,並且這些綱要的 URI 可以用於指示版本資訊。當與支援使用媒體類型參數指示綱要的媒體類型一起使用時,這些版本化的綱要 URI 可用於內容協商。

資源可以指示它是多個綱要的實例,這允許同時支援多個相容版本。然後,用戶端應用程式可以使用它識別的超綱要,並忽略較新或較舊的版本。

A.2. 回應和錯誤

由於超綱要一次代表一個資源,因此它不提供對使用連結執行的協定操作的所有可能回應的列舉。每個回應,包括錯誤,都被視為它自己的(可能是匿名的)資源,並且應該識別它自己的超綱要,並且可以選擇使用適當的媒體類型,例如 RFC 7807 的 "application/problem+json" [RFC7807],以允許使用者代理或用戶端應用程式解釋超出協定自身狀態報告所提供的任何資訊。

A.3. API 超綱要的靜態分析

可以靜態分析一組超綱要而無需實例資料,以便產生諸如文件或程式碼之類的輸出。但是,在沒有執行時間實例資料的情況下,無法存取驗證和超綱要的完整功能集。

這是一個有意的設計選擇,旨在為超媒體系統提供最大的執行時間靈活性。JSON 綱要作為一種媒體類型,允許為靜態分析和內容產生建立額外的詞彙,而本規範中未涉及這些詞彙。此外,如果完整的設計時描述是一個目標,則單個系統可能會將其使用限制為可以靜態分析的子集。[CREF12]已經提出了用於 API 文件和其他目的的詞彙,歡迎在 https://github.com/json-schema-org/json-schema-vocabularies 上提出貢獻。

附錄 B. 變更日誌

[CREF13]本節將在離開 Internet-Draft 狀態之前刪除。

draft-handrews-json-schema-hyperschema-01

draft-handrews-json-schema-hyperschema-00

draft-wright-json-schema-hyperschema-01

draft-wright-json-schema-hyperschema-00

draft-luff-json-hyper-schema-00

作者地址

Henry Andrews (編輯) Cloudflare, Inc. 舊金山, CA 美國 電子郵件:[email protected]
Austin Wright (編輯) 電子郵件:[email protected]