網際網路工程任務組 H. Andrews, Ed.
網路草案
預定狀態:資訊性 A. Wright, Ed.
截止日期:2020 年 3 月 20 日 2019 年 9 月 17 日

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

摘要

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) 的工作文件。請注意,其他群組也可能會以網路草案的形式散發工作文件。目前網路草案的清單位於 https://datatracker.ietf.org/drafts/current/。

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

本網路草案將於 2020 年 3 月 20 日到期。

著作權聲明

著作權 (c) 2019 IETF Trust 和被標識為文件作者的人員。保留所有權利。

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


目錄

1. 簡介

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

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

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

本規範將使用 JSON 綱要核心JSON 綱要驗證規範定義的概念、語法和術語。建議讀者準備這些規範的副本。

2. 符號慣例

本文檔中的關鍵字「必須 (MUST)」、「不得 (MUST NOT)」、「必要 (REQUIRED)」、「應 (SHALL)」、「不得 (SHALL NOT)」、「應該 (SHOULD)」、「不應該 (SHOULD NOT)」、「建議 (RECOMMENDED)」、「可以 (MAY)」和「可選 (OPTIONAL)」應按照 RFC 2119 中的描述進行解釋。

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 節的基本 URI 是「https://example.com/api/」,則「https://example.com/api/thing/1234」是產生的連結的目標 URI。

3.1. 術語

術語「綱要」、「實例」和「後設綱要」應按照 JSON 綱要核心規範中定義的方式進行解釋。

術語「適用」和「附加」應按照 JSON 綱要核心規範第 3.1 節中定義的方式進行解釋。

術語「連結」、「連結內容」(或「內容」)、「連結目標」(或「目標」)和「目標屬性」應按照 RFC 8288 第 2 節中定義的方式進行解釋。

術語「使用者代理程式」應按照 RFC 7230 第 2.1 節中定義的方式進行解釋,並廣泛適用於超媒體系統中可能使用的任何協定,而不僅僅是 HTTP 用戶端。

本規範定義以下術語

JSON 超媒體綱要
使用本規範定義的關鍵字的 JSON 綱要。
超媒體綱要
在本文檔中,術語「超媒體綱要」始終指的是 JSON 超媒體綱要
連結有效性
實例的有效連結是適用於該實例,且未違反連結描述物件中關鍵字施加的任何要求的連結。請注意,當使用「if」或「oneOf」(來自核心規範)等關鍵字來描述根據表示法的結構或值而為條件的連結時,可能會發生無效連結。
通用使用者代理程式
使用者代理(user agent)可以用於與任何伺服器上的任何資源互動,只要這些資源符合其支援的標準連結關係、媒體類型、URI 方案和協定;雖然它可能可以擴充以特別處理特定媒體類型的設定檔。
客戶端應用程式(client application)
一種為了特定目的而使用超媒體系統的應用程式。此類應用程式本身也可能是使用者代理,或者它可以建立在通用使用者代理之上。客戶端應用程式會針對其應用程式領域的特定連結關係、媒體類型、URI 方案、協定和資料結構進行程式設計。
客戶端輸入(client input)
透過使用者代理提供,且通常也透過客戶端應用程式提供的資料。此類資料可能會以互動方式從使用者請求,或在互動前以命令列引數、組態檔或原始程式碼中的硬式編碼值等形式提供。
操作(operation)
超連結的特定用途,例如發出網路請求(對於具有諸如 "http://" 等表示協定的方案的 URI),或根據連結採取其他動作(從 "data:" URI 讀取資料,或根據 "mailto:" 連結建構電子郵件訊息)。對於支援多種方法的協定(例如 HTTP),每種方法都被視為同一連結上的單獨操作。

3.2. 功能

JSON Hyper-Schema 實作能夠接收超綱要、實例,在某些情況下還能接收客戶端輸入,並產生一組完全解析過的有效連結。如 RFC 8288 第 2 節 所定義,連結包含內容、類型化關係、目標,以及選擇性的額外目標屬性。

關係類型和目標屬性直接取自每個連結的連結描述物件。內容和目標識別碼是根據 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/2019-09/hyper-schema#>

此詞彙(稱為 Hyper-Schema 詞彙)的目前 URI 為:<https://json-schema.dev.org.tw/draft/2019-09/vocab/hyper-schema>

對應的元綱要的目前 URI(與上面的便利元綱要不同之處在於,它僅描述超綱要關鍵字(「base」和「link」))為:<https://json-schema.dev.org.tw/draft/2019-09/meta/hyper-schema>

連結描述格式 可以在沒有 JSON Schema 的情況下使用,並且可以透過參考規範連結描述綱要作為使用連結的資料結構的綱要來宣告此格式的使用。規範連結描述綱要的 URI 為:<https://json-schema.dev.org.tw/draft/2019-09/links#>

JSON Hyper-Schema 實作可以自由地以任何格式提供輸出。但是,定義了一種特定的格式,用於符合性測試套件中,也用於說明 「實作需求」 中的重點,並顯示 範例 產生的輸出。建議實作能夠以這種格式產生輸出,以方便測試。描述建議輸出格式的 JSON Schema 的 URI 為 <https://json-schema.dev.org.tw/draft/2019-09/output/hyper-schema#>

可能會在規格草案之間發布更新的詞彙和元綱要 URI,以更正錯誤。實作應考慮在此規格草案之後且在下一個規格草案之前的日期所使用的 URI,以表示與此處列出的相同的語法和語義。

5. 綱要關鍵字

JSON Schema 核心的第 3.1 節 所定義,適用於實例中位置的所有綱要的超綱要關鍵字可以與該實例一起使用。

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

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

5.1. base

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

當解析為與「anchor」一起使用時,解析「base」範本的過程可能與解析為與「href」一起使用時不同,這在 URI 範本部分中會詳細說明。

5.2. links

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

6. 連結描述物件

連結描述物件 (LDO) 是 RFC 8288 第 2 節 中定義的抽象連結模型的序列化。如該文件中所述,連結包含內容、關係類型、目標,以及選擇性的目標屬性。 JSON Hyper-Schema 的 LDO 提供了所有這些內容,以及使用 JSON Schema 以各種方式描述用於連結的輸入的其他功能。

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

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

連結描述物件必須是物件,並且必須存在 「href」「rel」 屬性。本節將簡要介紹每個關鍵字,並在文件的後面部分提供其他用法說明和綜合範例。

6.1. 連結內容

在 JSON Hyper-Schema 中,連結的內容資源預設為連結附加到的子實例(如 JSON Schema 核心規格的第 3.1 節 所定義)。這通常不是整個實例文件。可以使用本節中的關鍵字變更此預設內容。

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

實作必須能夠建構連結內容的 URI,以及(如果需要完全識別)根據 RFC 6901 第 5 節 的規定,以字串表示形式取代 URI 片段的 JSON 指標。在 URI 範本部分中給出了基於 URI 範本建構 URI 的過程。

6.1.1. anchor

此屬性設定連結的內容 URI。此屬性的值是 URI 範本,並且產生的 URI 參考必須針對實例的基底 URI 進行解析。

URI 是使用與 「href」 屬性所述相同的過程,從提供的 URI 範本計算出來的,但 「hrefSchema」 不得套用。與目標 URI 不同,內容 URI 不接受使用者輸入。

6.1.2. anchorPointer

此屬性變更實例中被視為連結內容資源的點。此屬性的值必須是有效的 JSON 字串表示形式 JSON 指標,或是根據預設內容評估的有效相對 JSON 指標

雖然最好使用 「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」連結

根據 RFC 4287 的 4.2.7.2 節 最初的定義,「self」連結表示目標 URI 指向的資源與連結上下文等效。在 JSON Hyper-Schema 中,「self」連結必須可從實例解析,因此不得存在「hrefSchema」。

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

Hyper-schema 實作必須識別出關係類型為「self」的連結,其整個目前實例文件作為其上下文,描述使用者代理如何與該實例文件表示的資源互動。

6.2.3. 「collection」和「item」連結

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

實作必須將「collection」連結的目標和「item」連結的上下文識別為集合。

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

由於這種方法對應於 JSON Hyper-Schema 的資料提交概念,因此連結的 「submissionSchema」 欄位應與集合項目表示的 schema 相容,如「item」連結的目標資源或「collection」連結上下文資源的「self」連結所指示。

6.2.4. 使用擴充關係類型

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

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

6.3. 連結目標

目標 URI 模板用於識別連結的目標,可能會使用實例資料。此外,使用 「hrefSchema」,此模板可以根據用戶端輸入識別一組可能使用的目標資源。解析 URI 模板的完整過程(無論有無用戶端輸入)將在 URI 模板化章節中介紹。

6.3.1. href

「href」連結描述屬性的值是一個模板,用於確定相關資源的目標 URI。實例屬性的值必須針對實例的基本 URI 解析為 URI 參考

此屬性為必要屬性。

6.4. 調整 URI 模板解析

當解析 hyper-schema 中涉及的所有 URI 模板時,會使用本節中的關鍵字:「base」、「anchor」和「href」。請參閱 URI 模板化章節,了解完整的模板解析演算法。

請注意,當解析「base」模板時,解析開始的附加點是需要解析「base」模板的「href」或「anchor」關鍵字的附加點,而不是「base」關鍵字本身的附加點。

6.4.1. templatePointers

「templatePointers」連結描述屬性的值必須是一個物件。物件中的每個屬性值必須是有效的 JSON 指標,或相對於正在解析模板的連結附加點評估的有效 相對 JSON 指標

對於物件中與正在解析的模板中的變數名稱相符的每個屬性名稱,該屬性的值會調整該變數的變數解析起始位置。不符合正在解析的模板中變數名稱的屬性必須忽略。

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 的媒體類型,預期在擷取此資源時會返回該媒體類型。此屬性值也可能是媒體範圍,使用 RFC 7231 第 5.3.2 節 - HTTP「Accept」標頭中定義的相同模式。

此屬性類似於其他連結序列化格式的「type」屬性。使用者代理可能會使用此資訊在跟隨連結之前通知他們向使用者呈現的介面,但不應在解譯產生的資料時使用此資訊。相反地,使用者代理必須使用回應提供的媒體類型進行執行時間解譯。有關濫用「targetMediaType」的詳細檢查,請參閱 「安全考量」 章節。

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

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

6.5.4. targetSchema

此屬性提供一個預期描述連結目標表示法的 schema。根據協定,schema 可能會或可能不會描述使用連結執行的任何特定操作的請求或回應。請參閱 JSON Hyper-Schema 和 HTTP 章節,深入討論如何將此關鍵字與 HTTP 搭配使用。

6.5.5. targetHints

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

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

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

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

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

實作不得假設此物件中已考慮到所有可發現的資訊。用戶端應用程式必須正確處理與此屬性值衝突的執行時間回應。

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

有關將此關鍵字與 HTTP 和類似協定搭配使用的指南,請參閱 「JSON Hyper-Schema 和 HTTP」

6.6. 連結輸入

有四種方法可以使用連結的用戶端輸入,每種方法都由單獨的連結描述物件關鍵字處理。執行操作時,使用者代理應忽略與其語意不相關的 schema。

6.6.1. hrefSchema

「hrefSchema」連結描述屬性的值必須是有效的 JSON Schema。此 schema 用於驗證使用者輸入或其他使用者代理程式資料,以填寫 「href」 中的 URI 範本。

省略「hrefSchema」或將整個 schema 設定為「false」會阻止接受任何使用者代理程式資料。

將適用於特定變數的任何子 schema 設定為 JSON 字面值「false」會阻止接受該單一變數的任何使用者代理程式資料。

對於可以從實例資料解析的範本變數,如果實例資料對「hrefSchema」中所有適用的子 schema 都有效,則必須使用它來預先填入該變數的輸入資料集。

請注意,即使資料是從實例預先填入的,「hrefSchema」中該變數的驗證 schema 不必與適用於實例資料位置的驗證 schema 相同。這允許對使用者代理程式資料使用不同的驗證規則,例如支援日期時間輸入的拼寫月份,但使用標準日期時間格式進行儲存。

在接受輸入後(可能會覆蓋預先填入的實例資料),產生的資料集必須成功地針對「hrefSchema」的值進行驗證。如果驗證失敗,則不得使用該連結。如果驗證成功,則繼續執行「URI 範本」部分中給出的程序,並使用此更新的資料集。

6.6.2. headerSchema

[CREF2]與「targetHints」一樣,這個關鍵字在某種程度上規格不明確,以鼓勵實驗和回饋,因為我們試圖平衡彈性和清晰度。

如果存在,此屬性是協定特定的請求標頭或類似的控制和中繼資料的 schema。此物件的值必須是有效的 JSON Schema。協定由「href」URI scheme 決定,但請注意,不保證可以透過此協定存取資源。此 schema 僅供參考;目標資源的行為不受其存在的約束。

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

JSON 資料模型到標頭的確切映射取決於協定。但是,在大多數情況下,此 schema 應指定「object」類型,並且屬性名稱應為控制資料欄位名稱的小寫形式。與「targetHints」一樣,這些值應描述為陣列,以允許多個值,即使只期望一個值。

有關將此關鍵字與 HTTP 和類似協定一起使用的詳細指南,請參閱 「JSON Hyper-Schema 和 HTTP」 部分。

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

6.6.3. 操作目標資源表示

在 JSON Hyper-Schema 中,「targetSchema」 提供目標資源表示的非權威性描述。客戶端應用程式可以使用「targetSchema」來結構化用於取代或修改表示的輸入,或作為基於修補媒體類型的建立修補文件之基礎表示。

或者,如果缺少「targetSchema」,或者如果客戶端應用程式偏好僅使用權威資訊,則它可以與目標資源互動以確認或發現其表示結構。

「targetSchema」不打算描述連結操作回應,除非回應語義表示它是目標資源的表示。在所有情況下,回應本身指示的 schema 是權威性的。有關詳細範例,請參閱 「JSON Hyper-Schema 和 HTTP」

6.6.4. 提交資料以進行處理

「submissionSchema」「submissionMediaType」 關鍵字描述目標資源實作的處理函數的網域。否則,如上所述,對於與其無關的操作,將忽略提交 schema 和媒體類型。

6.6.4.1. submissionMediaType

如果存在,此屬性表示客戶端應用程式和使用者代理程式應針對 「submissionSchema」 描述的請求有效負載使用的媒體類型格式。

省略此關鍵字的行為與值為 application/json 相同。

請注意,「submissionMediaType」和「submissionSchema」不限於 HTTP URI。[CREF3]此聲明可能會移至範例結束的位置。

6.6.4.2. submissionSchema

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

這是一個與 「targetSchema」 屬性不同的概念,後者描述目標資訊資源(包括在 PUT 請求中取代資源內容),而「submissionSchema」描述使用者提交的請求資料,以供資源評估。「submissionSchema」旨在與那些有效負載不一定根據目標表示定義的請求一起使用。

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

7. 實作要求

在高階層面,符合規範的實作將滿足以下要求。每個要求都會在個別的關鍵字章節和關鍵字群組概述中詳細說明。

請注意,關於實作必須如何識別「self」、「collection」和「item」連結的要求,已在 連結關係類型 章節中完整涵蓋,此處不再重複。

雖然它不是實作的強制格式,但測試套件中使用的輸出格式總結了每個連結在使用前需要計算的內容

contextUri
內容資源的完整解析 URI(具有 scheme)。如果內容不是整個資源,並且存在可用的片段識別符語法,則 URI 包括片段。請注意,對於 application/json,沒有這樣的語法。
contextPointer
內容資源實例中位置的 JSON Pointer。如果實例媒體類型支援 JSON Pointer 作為片段識別符,則此指標將與編碼在「contextUri」欄位片段中的指標相同。
rel
連結關係類型。當多個連結關係類型出現在 LDO 中時,為了產生輸出,它們應被視為多個 LDO,每個 LDO 具有單一連結關係類型,但在其他方面相同。
targetUri
目標資源的完整解析 URI(具有 scheme)。如果連結接受輸入,則只有在提供輸入後才能產生此 URI。
hrefInputTemplates
接受輸入的連結的部分解析 URI 參考列表。列表中的第一個條目是部分解析的「href」。其他條目(如果有的話)是部分解析的「base」值,按從最直接到 schema 根的順序排列。在輸入中預先填入的範本變數在此階段未解析,因為預先填入的值可以被覆蓋。
hrefPrepopulatedInput
使用者代理程式應用於預先填入任何輸入機制,然後再接受客戶端輸入的資料集。如果要接受輸入,但沒有欄位要預先填入,則這將是一個空物件。
attachmentPointer
連結附加到的實例中位置的 JSON Pointer。預設情況下,「contextUri」和「attachmentPointer」相同,但是「contextUri」可以由 LDO 關鍵字更改,而「attachmentPointer」不能。

其他未參與產生上述資訊的 LDO 關鍵字,在產生測試套件的輸出時,會完全按照它們的顯示方式包含在內。除非特別相關,否則此處不會進一步討論這些欄位。

7.1. 連結探索和查找

在使用連結之前,必須透過將 hyper-schema 應用於實例並找到所有適用且有效的連結來發現它們。請注意,除了收集有效的連結之外,解析每個 LDO 的 URI 範本所需的任何 「base」 值也必須找到,並透過對實作 URI 範本解析過程最有用的任何機制與 LDO 關聯。

實作必須支援透過其附件指標或內容指標查找連結,方法是執行查找或提供所有連結的集合,其中兩個指標都已確定,以便使用者代理程式可以自行實作查找。

在透過內容指標執行查找時,附加到同一陣列元素的連結必須以與它們附加到的陣列元素相同的順序返回。

7.2. URI 範本

三個 hyper-schema 關鍵字是 URI 範本:「base」、「anchor」和「href」。每個關鍵字都會單獨解析為 URI 參考,然後根據 base 解析 anchor 或 href URI 參考(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:
        templateData[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 作者應謹記這一點,如果確切的表示形式很重要,則應使用其他類型(例如字串或布林值)。如果數字是以字串形式提供的輸入,則應使用作為輸入的字串。

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

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

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

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

無法辨識的關鍵字應提供給使用者代理使用,否則必須忽略。

7.4. 請求

超綱要實作應提供建構目標資源的所有有效請求所需的所有資訊。

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

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

不帶有主體有效負載的請求不需要其他關鍵字支援。

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

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

透過單一超媒體協定操作,將許多具有任意不同請求結構的應用程式操作導向到 RPC 系統,不在 JSON 超綱要等超媒體格式的範圍內。

7.5. 回應

作為一種超媒體格式,JSON 超綱要關注描述資源,包括詳細描述其連結,以便發出所有有效請求。它不關注直接描述這些請求的所有可能回應。

如同任何超媒體系統一樣,回應應具有自我描述性。在超綱要的上下文中,這表示每個回應都必須連結其自己的超綱要。雖然預期由目標資源的表示形式組成的回應會針對 "targetSchema" 和 "targetMediaType" 進行驗證,但是這些關鍵字僅作為建議,如果與回應本身衝突,則必須忽略。

其他回應(包括錯誤回應、複雜的重新導向和處理狀態表示形式)也應連結到它們自己的綱要,並使用適當的媒體類型(例如,錯誤的 "application/problem+json")。某些錯誤可能不會連結綱要,因為它們是由不知道超綱要的中介機構產生的,而不是由來源產生的。

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

在設計時靜態對應所有可能的回應及其綱要不在 JSON 超綱要的範圍內,但可能在其他基於超綱要的 JSON 綱要詞彙的範圍內(請參閱 附錄 A.3)。

7.6. 串流剖析器

當與串流剖析器一起使用時,根據連結的上下文探索連結,或使用連結的上下文識別集合的要求會帶來獨特的挑戰。如果未處理整個綱要和實例文件,則無法明確地滿足這些要求。

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

8. JSON 超綱要和 HTTP

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

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

JSON 綱要核心規格的第 13 節提供了關於在超媒體系統中將實例連結到其綱要的指導。這可以使用網路可存取的綱要來完成,也可以僅識別預先封裝在用戶端應用程式中的綱要。JSON 超綱要有意不限制此機制,儘管建議盡可能使用核心規格中概述的技術。

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

連結描述物件不會直接指出目標資源支援哪些操作,例如 HTTP 方法。相反,操作應主要從連結 關係類型 和 URI 協定中推斷。

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

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

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

8.2. "targetSchema" 和 HTTP

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

由於許多 HTTP 方法的語義是根據目標資源定義的,因此對於多種 HTTP 方法的請求和/或回應,會使用 "targetSchema"。 特別是,"targetSchema" 指示客戶端應用程式可以預期 HTTP GET 回應的內容,或任何 "Content-Location" 標頭等於請求 URI 的回應,以及如果客戶端應用程式使用 HTTP PUT 請求建立或替換資源時應傳送的內容。這些關聯在 RFC 7231 第 4.3.1 節 - "GET"、第 4.3.4 節 "PUT" 以及第 3.1.4.2 節 "Content-Location" 中定義。

根據 RFC 5789,HTTP PATCH 的請求結構由 "targetSchema" 和請求媒體類型的組合決定,請求媒體類型由 "Accept-Patch" 標頭傳達,該標頭可能包含在 "targetHints" 中。適合用於 PATCH 的媒體類型定義了一種表達文件變更的語法,該語法可以應用於 "targetSchema" 所描述的表示,以確定語法上有效的請求酬載集。通常,驗證 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 回應一樣,回應中的任何表示都應連結到其自身的超架構,以指示如何處理它。如 附錄 A.2 中所述,將超連結與所有可能的操作回應連線不在 JSON Hyper-Schema 的範圍內。

8.4. 使用 "targetHints" 優化 HTTP 可探索性

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

HTTP 回應標頭資訊的 JSON 序列化應遵循正在進行的 "HTTP 標頭欄位值的 JSON 編碼" 中建立的準則。該文件中範例中顯示的方法應盡可能應用於其他結構相似的標頭。

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

建議架構作者在適用的情況下提供以下類型 HTTP 標頭值的提示:

一般來說,可能在不同時間具有不同值的標頭不應包含在 "targetHints" 中。

例如,允許 HEAD、GET 和 POST 的 Allow 標頭將顯示如下:

{
    "targetHints": {
        "allow": ["HEAD", "GET", "POST"]
    }
}

                    

請注意,無論是具有逗號分隔值的單行 Allow 標頭、每行一個值的多個 Allow 標頭,還是這些排列的任何組合,此表示方式都相同。與 HTTP 標頭通常情況一樣,逗號分隔的值和標頭的多個出現方式以相同的方式處理。

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

架構應編寫為描述遵循正在進行的 "HTTP 標頭欄位值的 JSON 編碼" 中建立準則的 JSON 序列化。該文件中範例中顯示的方法應盡可能應用於其他結構相似的標頭。

建議架構作者在適用的情況下描述以下類型 HTTP 標頭的可用用法:

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

8.6. 透過集合建立資源

在使用 HTTP 或諸如 CoAP 之類的與 HTTP 明確相似的協定時,這是透過將要建立的個別資源的表示 POST 到集合資源來完成的。識別集合和項目資源的過程在 第 6.2.3 節中描述。

8.7. 內容協商和架構演進

JSON Hyper-Schema 有助於 HTTP 內容協商,並允許主動和被動策略的混合。如上所述,超架構可以包含 HTTP 標頭的架構,例如帶有 "headerSchema" 關鍵字的 "Accept"、"Accept-Charset"、"Accept-Language" 等。使用者代理或客戶端應用程式可以使用此架構中的資訊(例如,支援語言的列舉清單),而不是發出初始請求以啟動被動協商過程。

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

對於允許將架構指定為媒體類型參數的媒體類型,在請求中傳送或在 "headerSchema" 中宣告的 "Accept" 值可以包括預期協商表示符合的架構 URI。內容協商中架構參數的一種可能用途是,如果資源在過去曾符合多個不同的架構版本。客戶端應用程式可以透過這種方式在 "Accept" 標頭中指示它理解的版本。

9. 範例

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

大多數其他關鍵字不是直接的("title" 和 "description"),就是將驗證應用於特定種類的輸入、請求或回應,或者具有協定特定的行為。示範 HTTP 用法的範例在附錄中提供。

9.1. 進入點連結,無範本

在此範例中,我們將假設一個具有記錄的進入點 URI https://example.com/api 的範例 API,這是一個空的 JSON 物件,其中包含指向架構的連結。這裡,進入點本身沒有任何數據,只存在以提供初始連結集。

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

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

                    

連結的超架構定義了 API 的基本 URI,並提供兩個連結:指向 API 文件的 "about" 連結和指示這是基本 URI 架構的 "self" 連結。

{
    "$id": "https://schema.example.com/entry",
    "$schema": "https://json-schema.dev.org.tw/draft/2019-09/hyper-schema",
    "base": "https://example.com/api/",
    "links": [
        {
            "rel": "self",
            "href": "../api",
        }, {
            "rel": "about",
            "href": "docs"
        }
    ]
}
                    

這些是最簡單的連結,只有一個關聯類型和一個沒有範本變數的 "href"。它們解析如下:

由於 RFC 3986 URI 參考解析演算法的特性,"api" 在基本和 "self" 連結中 "../api" href 中重複。為了使相對 URI 參考通常運作良好,基本 URI 需要包含尾部斜線。"about" 連結及其 "docs" href 顯示了相對參考的常見情況,該情況在本文件中其他範例中使用。

但是,如果 API 為其資源使用不帶尾部斜線的 URI,則無法提供僅刪除尾部斜線而不重複其上方的路徑元件的相對參考。這使得僅在尾部斜線方面與基本 URI 不同的進入點資源情況有些尷尬。

當然,資源 URI 可能有尾部斜線,但此範例旨在突顯這個經常令人困惑的特殊情況。

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

附件指標是根指標(對於執行個體為空物件的唯一可能性)。上下文 URI 是預設值,即請求的文件。由於 application/json 不允許片段,因此上下文指標對於完整描述上下文是必要的。它的預設行為與附件指標相同。

9.2. 個別識別的資源

讓我們在系統中新增 "things",從個別的 thing 開始:

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

我們的 "thing" 具有伺服器指派的 ID,這是建構 "self" 連結所必需的。它還具有 "data" 欄位,可以是任何類型。"$defs" 區段的原因將在下一個範例中清楚說明。

請注意,驗證架構不需要 "id",但 self 連結需要 "id"。這是合理的:只有在建立 "thing" 且伺服器指派了 ID 時,"thing" 才會有 URI。但是,您可以將此架構與僅包含 data 欄位的執行個體一起使用,這允許您驗證即將建立的 "thing" 執行個體。

讓我們在進入點架構中新增一個連結,如果您可以將其 ID 作為輸入,則可以直接跳轉到特定的 thing。為了節省空間,僅顯示新的 LDO。與 "self" 和 "about" 不同,沒有關於假設 thing 的 IANA 註冊關係,因此使用 "tag:" URI 方案定義了擴充關係

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

這裡的 "href" 值相同,但其他一切都不同。回想一下,執行個體是一個空物件,因此無法從執行個體資料解析 "id"。相反,它需要作為客戶端輸入。此 LDO 也可以使用 "templateRequired",但是由於 "hrefSchema" 中有 "required",因此嚴格來說不是必需的。在 "hrefSchema" 中不將 "id" 標記為必需的情況下提供 "templateRequired" 將導致錯誤,因為客戶端輸入是解析此連結的唯一可能來源。

9.3. 提交酬載並接受 URI 輸入

此範例涵蓋了如何使用 "submission" 欄位進行非表示輸入,以及如何將它們與使用輸入解析 URI 範本一起使用。與 HTML 表單不同,HTML 表單需要建構 URI 或傳送酬載,但不允許兩者同時進行,JSON Hyper-Schema 可以描述同一個連結上相同操作的兩種輸入。

「submissionSchema」和「submissionMediaType」欄位用於描述非目標資源表示法的酬載。當與「http(s)://」URI 一起使用時,它們通常指的是 POST 請求酬載,如HTTP 用法附錄中所見。

在這種情況下,我們使用「mailto:」URI,根據RFC 6068 第 3 節,它不提供任何檢索資源的操作。它只能用於建構要傳送的訊息。由於沒有可檢索、可取代或可刪除的目標資源的概念,因此不使用「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/2019-09/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://example.com/api/stuff」檢索的以下實例

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

在要求用戶端應用程式輸入之前,我們可以部分解析連結如下。

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

請注意取代「targetUri」的「href*」關鍵字。這些是涵蓋不同類型輸入的三種可能的「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://example.com/api/trees/1/nodes/123 HTTP/1.1

200 OK
Content-Type: application/json
Link: <https://example.com/api/trees/1/nodes/123>; rel="self"
Link: <https://example.com/api/trees/1/nodes/123>; rel="up";
        anchor="https://example.com/api/trees/1/nodes/456"
Link: <https://example.com/api/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 指標。

{
    "$id": "https://schema.example.com/tree-node",
    "$schema": "https://json-schema.dev.org.tw/draft/2019-09/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/2019-09/hyper-schema",
    "base": "https://example.com/api/",
    "type": "object",
    "required": ["data"],
    "properties": {
        "id": {"$ref": "#/$defs/id"},
        "data": true
    },
    "links": [
        {
            "rel": "self",
            "href": "things/{id}",
            "templateRequired": ["id"],
            "targetSchema": {"$ref": "#"}
        }, {
            "rel": "collection",
            "href": "/things",
            "targetSchema": {"$ref": "thing-collection#"},
            "submissionSchema": {"$ref": "#"}
        }
    ],
    "$defs": {
        "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/2019-09/hyper-schema",
    "base": "https://example.com/api/",
    "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://example.com/api/things",
        "contextPointer": "",
        "rel": "self",
        "targetUri": "https://example.com/api/things",
        "attachmentPointer": ""
    },
    {
        "contextUri": "https://example.com/api/things",
        "contextPointer": "/elements/0",
        "rel": "self",
        "targetUri": "https://example.com/api/things/12345",
        "attachmentPointer": "/elements/0"
    },
    {
        "contextUri": "https://example.com/api/things",
        "contextPointer": "/elements/1",
        "rel": "self",
        "targetUri": "https://example.com/api/things/67890",
        "attachmentPointer": "/elements/1"
    },
    {
        "contextUri": "https://example.com/api/things",
        "contextPointer": "",
        "rel": "item",
        "targetUri": "https://example.com/api/things/12345",
        "attachmentPointer": "/elements/0"
    },
    {
        "contextUri": "https://example.com/api/things",
        "contextPointer": "",
        "rel": "item",
        "targetUri": "https://example.com/api/things/67890",
        "attachmentPointer": "/elements/1"
    },
    {
        "contextUri": "https://example.com/api/things",
        "contextPointer": "/elements/0",
        "rel": "collection",
        "targetUri": "https://example.com/api/things",
        "attachmentPointer": "/elements/0"
    },
    {
        "contextUri": "https://example.com/api/things",
        "contextPointer": "/elements/1",
        "rel": "collection",
        "targetUri": "https://example.com/api/things",
        "attachmentPointer": "/elements/1"
    }
]

                    

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

有三個「self」連結,一個用於集合,一個用於「elements」陣列中的每個項目。項目「self」連結在以「$ref」參照的個別「thing」結構描述中定義。這三個連結可以通過它們的內容或附加指標來區分。我們將在9.5.2 節中重新探討集合「self」連結的「submissionSchema」。

有兩個「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": "#/$defs/pagination"},
                "current": {"$ref": "#/$defs/pagination"},
                "next": {"$ref": "#/$defs/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": "#"}
        }
    ],
    "$defs": {
        "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://example.com/api/things",
        "contextPointer": "",
        "rel": "self",
        "targetUri":
            "https://example.com/api/things?offset=0&limit=2",
        "attachmentPointer": ""
    },
    {
        "contextUri": "https://example.com/api/things",
        "contextPointer": "",
        "rel": "next",
        "targetUri":
            "https://example.com/api/things?offset=3&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#/$defs/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 issue #421 以獲取更多討論。 [CREF9]超綱要的 Draft-04 定義了一個「create」連結關係,其上下文是綱要,而不是實例。這不符合基於實例的連結模型,並且錯誤地使用了操作名稱作為連結關係類型。但是,定義從綱要到集合實例的更正確設計的連結可能是解決此問題的一種方法。同樣,請參閱 GitHub issue #421 以獲取更多詳細資訊。

10. 安全性考量

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

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 issue #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. 規範性參考文獻

[json-schema] Wright, A.H. Andrews, "JSON 綱要:描述 JSON 文件的媒體類型", Internet-Draft draft-handrews-json-schema-02, 2017 年 11 月。
[json-schema-validation] Wright, A., Andrews, H.G. Luff, "JSON 綱要驗證:JSON 結構驗證的詞彙", Internet-Draft draft-handrews-json-schema-validation-02, 2017 年 11 月。
[relative-json-pointer] Luff, G.H. Andrews, "相對 JSON 指標", Internet-Draft draft-handrews-relative-json-pointer-02, 2018 年 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 月。

12.2. 參考性參考文獻

[I-D.reschke-http-jfv] Reschke, J., "HTTP 標頭欄位值的 JSON 編碼", Internet-Draft draft-reschke-http-jfv-06, 2017 年 6 月。
[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 月。

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

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

超綱要一次只關注一個資源和一組相關連結。就像網頁瀏覽器一次只處理一個 HTML 頁面一樣,而不論該頁面是否或如何作為「網站」的一部分運作,一個具備超綱要感知的使用者代理程式一次只處理一個資源,而不論該資源是否或如何適合 API。

因此,超綱要適合在 API 內部使用,但不適合將 API 作為完整的實體本身進行描述。它無法描述 API 範圍的概念,而只能描述資源和連結範圍的概念,並且這些描述超出 JSON 超綱要的界限。

A.1. 使用超綱要的資源演變

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

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

A.2. 回應與錯誤

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

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

可以靜態分析一組超綱要,而無需實例數據,以便產生文件或程式碼等輸出。但是,如果沒有執行階段實例數據,則無法存取驗證和超綱要的完整功能集。

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

附錄 B. 更新日誌

[CREF13]在離開網路草案狀態之前,本節將被移除。

draft-handrews-json-schema-hyperschema-02

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 (編輯) 電子郵件: [email protected]
Austin Wright (編輯) 電子郵件: [email protected]