インターネット技術タスクフォース H.アンドリュース、編
インターネットドラフト
対象ステータス:情報提供 A.ライト、編
失効: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.dokyumento.jp/>を参照してください。

フィードバックを提供するには、この課題トラッカー、ホームページに記載されているコミュニケーション方法、またはドキュメント編集者にメールで連絡してください。

このメモのステータス

このインターネットドラフトは、BCP 78およびBCP 79の規定に完全に準拠して提出されています。

インターネットドラフトは、インターネット技術タスクフォース(IETF)のワーキングドキュメントです。他のグループもインターネットドラフトとしてワーキングドキュメントを配布する場合があることに注意してください。現在のインターネットドラフトのリストは、https://datatracker.ietf.org/drafts/current/ にあります。

インターネットドラフトは、最大6か月間有効なドラフトドキュメントであり、いつでも他のドキュメントによって更新、置換、または廃止される可能性があります。インターネットドラフトを参考資料として使用したり、「作業中」以外で引用したりすることは不適切です。

このインターネットドラフトは、2020年3月20日に失効します。

著作権表示

Copyright(c)2019 IETF Trustおよびドキュメント作成者として特定された個人。全著作権所有。

このドキュメントは、BCP 78およびこのドキュメントの発行日に有効なIETFドキュメントに関するIETFトラストの法的規定(https://trustee.ietf.org/license-info)に従います。このドキュメントに関するあなたの権利と制限について説明していますので、これらのドキュメントを注意深く確認してください。このドキュメントから抽出されたコードコンポーネントには、トラスト法的規定のセクション4.eに記載されている簡易BSDライセンステキストが含まれている必要があり、簡易BSDライセンスに記載されているように保証なしで提供されます。


目次

1. はじめに

JSONハイパースキーマは、ハイパーメディア環境(HTTPなど)を介してリモートJSONリソースを処理および操作するためのハイパーリンクと命令で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」という名前の1つの既知のオブジェクトフィールドを持つインスタンスから構築されます。

{
    "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」(コア仕様から)などのキーワードを使用して、表現の構造または値に依存する条件付きリンクを記述する場合に発生する可能性があることに注意してください。
汎用ユーザーエージェント
サポートしている標準化されたリンク関係、メディアタイプ、URIスキーム、およびプロトコルの中から、任意のサーバーの任意のリソースと対話するために使用できるユーザーエージェント。ただし、メディアタイプの特定のプロファイルを特別に処理するように拡張できる場合があります。
クライアントアプリケーション
特定の目的のためにハイパーメディアシステムを使用するアプリケーション。このようなアプリケーションは、それ自体がユーザーエージェントである場合もあれば、汎用ユーザーエージェントの上に構築される場合もあります。クライアントアプリケーションは、そのアプリケーションのドメインに固有のリンク関係、メディアタイプ、URIスキーム、プロトコル、およびデータ構造に関する知識を使ってプログラミングされています。
クライアント入力
ユーザーエージェントを通じて、多くの場合、クライアントアプリケーションを通じて提供されるデータ。このようなデータは、ユーザーからインタラクティブに要求される場合もあれば、コマンドライン引数、設定ファイル、またはソースコード内のハードコードされた値などの形式で、インタラクションの前に提供される場合もあります。
オペレーション
ネットワークリクエスト(プロトコルを示す「http://」などのスキームを持つURIの場合)を実行したり、リンクに基づいてアクションを実行したりする(「data:」URIからデータを読み取る、または「mailto:」リンクに基づいて電子メールメッセージを作成するなど)、ハイパーリンクの特定の用途。複数のメソッドをサポートするHTTPなどのプロトコルの場合、各メソッドは同じリンクに対する別個のオペレーションとみなされます。

3.2. 機能

JSONハイパースキーマの実装は、ハイパースキーマ、インスタンス、場合によってはクライアント入力を受け取り、完全に解決された有効なリンクのセットを生成できます。RFC 8288、セクション2で定義されているように、リンクはコンテキスト、型付きの関係、ターゲット、およびオプションで追加のターゲット属性で構成されます。

関係タイプとターゲット属性は、各リンクのリンク記述オブジェクトから直接取得されます。コンテキストとターゲット識別子は、URIテンプレート、インスタンスデータ、および(ターゲット識別子の場合)クライアント入力の組み合わせから構築されます。

ターゲットは常にURIによって完全に識別されます。JSON Hyper-Schemaで使用できるapplication/jsonや他の多くのメディアタイプにはURIフラグメント識別子の構文がないため、コンテキストはURIによって部分的にしか識別されない場合があります。このような場合、残りの識別はJSONポインタとして提供されます。

いくつかのIANA登録済みリンク関係タイプには、JSONハイパースキーマドキュメントで特定のセマンティクスが与えられています。"self"リンクは、インスタンスドキュメントが表すリソースと対話するために使用され、"collection"および"item"リンクは、コレクション固有のセマンティクスを想定できるリソースを識別します。

4. メタスキーマと出力スキーマ

JSONハイパースキーマメタスキーマの現在のURIは<https://json-schema.dokyumento.jp/draft/2019-09/hyper-schema#>です。

ハイパースキーマボキャブラリーとして知られる、このボキャブラリーの現在のURIは<https://json-schema.dokyumento.jp/draft/2019-09/vocab/hyper-schema>です。

対応するメタスキーマの現在のURIは、上記の便宜的なメタスキーマとは異なり、ハイパースキーマキーワード("base"と"link")のみを記述しているのは<https://json-schema.dokyumento.jp/draft/2019-09/meta/hyper-schema>です。

リンク記述形式はJSONスキーマなしで使用でき、この形式の使用は、リンクを使用するデータ構造のスキーマとして、規範的なリンク記述スキーマを参照することで宣言できます。規範的なリンク記述スキーマのURIは<https://json-schema.dokyumento.jp/draft/2019-09/links#>です。

JSONハイパースキーマの実装は、任意の形式で出力できます。ただし、適合性テストスイートで使用するために特定の形式が定義されており、この形式は「実装要件」のポイントを説明したり、によって生成される出力を示したりするためにも使用されます。実装はテストを容易にするために、この形式で出力できることが推奨されます。推奨される出力形式を記述するJSONスキーマのURIは<https://json-schema.dokyumento.jp/draft/2019-09/output/hyper-schema#>です。

エラーを修正するために、仕様ドラフト間で更新されたボキャブラリーとメタスキーマのURIが公開される場合があります。実装では、この仕様ドラフト以降で次の仕様ドラフトより前の日付のURIは、ここにリストされている構文とセマンティクスと同じものを示すと見なす必要があります。

5. スキーマキーワード

JSONスキーマコアのセクション3.1で定義されているように、インスタンス内の位置に適用可能なすべてのスキーマからのハイパースキーマキーワードを、そのインスタンスで使用できます。

複数のサブスキーマが特定のサブインスタンスに適用可能な場合、すべての"link"配列は、任意の順序で、単一のセットに結合する必要があります。結果として得られるセット内の各オブジェクトは、同じスキーマと親スキーマからの適用可能な"base"値のリストを、解決順に保持する必要があります。

すべてのJSONスキーマキーワードと同様に、このセクションで説明されているすべてのキーワードはオプションです。最小限の有効なJSONハイパースキーマは、空のオブジェクトです。

5.1. base

存在する場合、このキーワードは最初にURIテンプレートとして解決され、次にインスタンスの現在のURIベースに対してURI参照として解決される必要があります。結果は、"base"を含むサブスキーマおよびその中のすべてのサブスキーマを処理する間、インスタンスの新しいURIベースとして設定される必要があります。

"base"テンプレートを解決するプロセスは、"anchor"で使用するために解決される場合と、"href"で使用するために解決される場合とで異なる可能性があり、これはURIテンプレートセクションで詳細に説明されています。

5.2. links

スキーマの"links"プロパティは、リンク記述オブジェクトをインスタンスに関連付けるために使用されます。このプロパティの値は配列でなければならず、配列内のアイテムは、以下で定義するようにリンク記述オブジェクトでなければなりません。

6. リンク記述オブジェクト

リンク記述オブジェクト(LDO)は、RFC 8288、セクション2で定義されている抽象リンクモデルのシリアル化です。そのドキュメントで説明されているように、リンクはコンテキスト、関係タイプ、ターゲット、およびオプションでターゲット属性で構成されます。JSONハイパースキーマのLDOは、これらすべてに加えて、JSONスキーマを使用してさまざまな方法でリンクで使用する入力を記述するための追加機能を提供します。

リンクコンテキストとターゲットを識別するためにURIテンプレートが使用され、ターゲットを識別するときにクライアント入力がさらに使用される可能性があるため、LDOは、JSONインスタンスドキュメントで使用すると複数のリンクに解決される可能性があるリンクテンプレートです。

LDOの特定の用途(通常、プロトコルを介したリクエストとレスポンスを含む)は、オペレーションと呼ばれます。多くのプロトコルでは、特定のリンクで複数のオペレーションが可能です。プロトコルは、ターゲットのURIスキームによって示されます。すべてのURIスキームが通信に使用できるプロトコルを示すわけではなく、そのようなプロトコルを示すURIスキームを持つリソースでさえ、そのプロトコルを介して利用できる必要はないことに注意してください。

リンク記述オブジェクトはオブジェクトでなければならず、"href"および"rel"プロパティが存在する必要があります。各キーワードは、このセクションで簡単に説明し、追加の使用方法の説明と包括的な例をドキュメントの後半で示します。

6.1. リンクコンテキスト

JSONハイパースキーマでは、リンクのコンテキストリソースは、デフォルトでは、リンクがアタッチされているサブインスタンスです(JSONスキーマコア仕様のセクション3.1で定義されているように)。これは、インスタンスドキュメント全体ではないことがよくあります。このデフォルトのコンテキストは、このセクションのキーワードを使用して変更できます。

インスタンスのメディアタイプによっては、正確なデフォルトのコンテキストリソースにURIを割り当てることが可能ではない場合があります。特に、application/jsonはURIフラグメント解決構文を定義していないため、プレーンJSONドキュメント内のプロパティまたは配列要素は、URIで完全に識別できません。完全なURIを生成できない場合、コンテキストの位置は、インスタンスドキュメントのURIとともに、別のプレーン文字列JSONポインターで伝える必要があります。

実装は、リンクコンテキストのURI、および(完全な識別に必要な場合)RFC 6901、セクション5に従って文字列表現形式のJSONポインタを、URIフラグメントの代わりに構築できる必要があります。URIテンプレートに基づいてURIを構築するプロセスについては、URIテンプレートセクションで説明します。

6.1.1. anchor

このプロパティは、リンクのコンテキストURIを設定します。プロパティの値はURIテンプレートであり、結果のURI参照はインスタンスのベースURIに対して解決される必要があります。

URIは、"href"プロパティで説明されているのと同じプロセスを使用して、提供されたURIテンプレートから計算されます。ただし、"hrefSchema"は適用してはならないという例外があります。ターゲットURIとは異なり、コンテキストURIはユーザー入力を受け入れません。

6.1.2. anchorPointer

このプロパティは、リンクのコンテキストリソースとみなされるインスタンス内のポイントを変更します。プロパティの値は、JSON文字列表現形式の有効なJSONポインタ、またはデフォルトのコンテキストに対して相対的に評価される有効な相対JSONポインタでなければなりません。

既知のURIを持つ別のコンテキストは"anchor"キーワードで設定するのが最適ですが、application/jsonにフラグメント識別子の構文がないため、通常はURIを使用してJSONインスタンス内のコンテキストを変更することはできません。

JSONポインタをフラグメント識別子構文として定義する"+json"メディアタイプの場合でも、デフォルトのコンテキストが配列内にネストされている場合、その同じネストされたJSONオブジェクト内の別のプロパティへのポインタを構築するために、その配列内のデフォルトのコンテキストの位置のインデックスを取得することはできません。これは例で示します。

このキーワードを処理した結果は、インスタンスのメディアタイプがそのようなフラグメントを許可する場合はURIフラグメントでなければなりません。それ以外の場合は、文字列エンコードされたJSONポインタでなければなりません。

6.2. リンク関係タイプ

リンクの関係タイプは、そのセマンティクスを識別します。これは、アプリケーションがリソースと対話する方法を伝えるための主要な手段です。

関係定義は通常、メディアタイプに依存せず、ユーザーは最も適切な既存の受け入れられた関係定義を利用することが推奨されます。

6.2.1. rel

このプロパティの値は、文字列または文字列の配列のいずれかでなければなりません。値が配列の場合、少なくとも1つの文字列を含んでいる必要があります。

各文字列は、RFC 8288のセクション2.1で定義されている単一のリンク関係タイプでなければなりません。また、別のリンク関係タイプの有無に基づいて追加のセマンティクスを推論すべきではないという制限を含みます。

このプロパティは必須です。

6.2.2. "self"リンク

RFC 4287のセクション4.2.7.2で最初に定義されたように、"self"リンクは、ターゲットURIがリンクコンテキストと同等のリソースを識別することを示します。JSONハイパースキーマでは、"self"リンクはインスタンスから解決可能でなければならないため、"hrefSchema"は存在してはなりません。

ハイパースキーマの作成者は、"self"リンクを使用に必要なすべてのインスタンスデータを持つようにするために、"templateRequired"を使用する必要があります。

ハイパースキーマの実装は、関係タイプ"self"を持つリンクが、現在のインスタンスドキュメント全体をコンテキストとして持つ場合、そのインスタンスドキュメントで表されるリソースとユーザーエージェントがどのように対話できるかを記述していることを認識する必要があります。

6.2.3. "collection"および"item"リンク

RFC 6573は、"item"および"collection"のリンク関係タイプを定義および登録しています。JSONハイパースキーマは、これらのタイプによって示されるコレクションリソースに追加のセマンティクスを課します。

実装は、"collection"リンクのターゲットと"item"リンクのコンテキストをコレクションとして認識する必要があります。

ハイパーメディアにおけるよく知られたデザインパターンは、コレクションリソースを使用してコレクションのメンバーを作成し、サーバーによって割り当てられたURIを与えることです。URIスキームによって示されるプロトコルが、サーバーによって割り当てられたURIを持つリソースを作成するのに適した特定のメソッドを定義している場合、これらのリンク関係タイプによって識別されるコレクションリソースは、コレクションメンバーの作成のセマンティクスと競合するようなメソッドのセマンティクスを定義してはなりません。コレクションリソースは、そのようなプロトコルメソッドを介してアイテムの作成を実装することができ、ユーザーエージェントは、そのような操作が存在する場合、アイテム作成のセマンティクスを持つと仮定することができます。

そのようなメソッドはJSONハイパースキーマのデータ送信の概念に対応するため、リンクの"submissionSchema"フィールドは、"item"リンクのターゲットリソースまたは"collection"リンクのコンテキストリソースの"self"リンクによって示されるように、コレクションのアイテムの表現のスキーマと互換性があるべきです。

6.2.4. 拡張関係タイプを使用する

("related"を除き)登録された関係が適用されない場合、ユーザーはRFC 8288のセクション2.1.2で説明されているように、独自の拡張関係タイプを定義することを推奨します。リンク関係タイプのURIを選択する最も簡単な方法は、システムの主要なリソースを識別するために既に使用されているURIスキームを使用するか、RFC 4151で定義されている"tag"などの人間が読める非デリファレンス可能なURIスキームを使用することです。

拡張関係タイプのURIは、それを許可するスキームを使用している場合でも、デリファレンス可能である必要はありません。

6.3. リンクターゲット

ターゲットURIテンプレートは、インスタンスデータを利用して、リンクのターゲットを識別するために使用されます。さらに、"hrefSchema"を使用すると、このテンプレートはクライアント入力に基づいて使用する可能性のあるターゲットリソースのセットを識別できます。クライアント入力の有無にかかわらず、URIテンプレートを解決する完全なプロセスについては、URIテンプレートのセクションで説明します。

6.3.1. href

"href"リンク記述プロパティの値は、関連リソースのターゲットURIを決定するために使用されるテンプレートです。インスタンスプロパティの値は、インスタンスのベースURIに対してURI参照として解決する必要があります。

このプロパティは必須です。

6.4. URIテンプレート解決の調整

このセクションのキーワードは、ハイパースキーマに関係するすべての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

このプロパティは、リンクターゲットの表現を記述することが予想されるスキーマを提供します。プロトコルによっては、スキーマはリンクで実行される特定の操作へのリクエストまたは応答を記述する場合があります。HTTPでのこのキーワードの使用方法に関する詳細な説明については、JSONハイパースキーマとHTTPのセクションを参照してください。

6.5.5. targetHints

[CREF1]このセクションでは、その構造の大部分をURIスキームで示されるプロトコルに委ねることにより、包括性と柔軟性のバランスをとろうとしています。リソースはデリファレンス可能なスキームを持つURIで識別できますが、そのプロトコルを介してアクセスできない場合があることに注意してください。現在非常に緩いですが、このセクションはドラフトフィードバックに基づいてより明確になることが期待されており、将来のドラフトで大幅に変更される可能性があります。

このプロパティの値は、アドバイザリのみです。これは、通常、HTTP HEADまたはOPTIONSリクエストへの応答で返されるヘッダーなどのプロトコル固有の制御情報またはメタデータの形式で、ターゲットリソースとの対話を通じて発見されることが予想される情報を表します。プロトコルは"href" URIスキームによって決定されますが、リソースがそのようなプロトコルを介してアクセスできるとは限らないことに注意してください。

このプロパティの値はオブジェクトである必要があります。このオブジェクトのキーは、制御データフィールド名の小文字形式である必要があります。各値は、複数値フィールドを均一に処理するために、配列である必要があります。複数の値は、単一の文字列としてではなく、配列として提示する必要があります。

JSONオブジェクトとしての表現に適さない制御情報を持つプロトコルは、配列などの別のデータ型で表すことができます。

示されたプロトコルの一部として理解できない値は、JSONハイパースキーマの実装によって無視する必要があります。アプリケーションはこのような値を利用することができますが、他の実装との相互運用性を想定してはなりません。

実装は、このオブジェクトですべての発見可能な情報が考慮されているとは想定してはなりません。クライアントアプリケーションは、このプロパティの値と矛盾するランタイム応答を適切に処理する必要があります。

クライアントアプリケーションは、実装がこのプロパティの値に基づいて自動的にアクションを実行すると想定してはなりません。

HTTPおよび類似のプロトコルでこのキーワードを使用するガイダンスについては、"JSONハイパースキーマとHTTP"を参照してください。

6.6. リンク入力

リンクでクライアント入力を使用する方法は4つあり、それぞれが個別のリンク記述オブジェクトキーワードで対処されています。操作を実行する場合、ユーザーエージェントは、そのセマンティクスに関連しないスキーマを無視する必要があります。

6.6.1. hrefSchema

"hrefSchema"リンク記述プロパティの値は、有効なJSONスキーマでなければなりません。このスキーマは、"href"のURIテンプレートに入力するためのユーザー入力または他のユーザーエージェントデータを検証するために使用されます。

"hrefSchema"を省略するか、スキーマ全体を"false"に設定すると、ユーザーエージェントデータは受け入れられません。

特定の変数に適用されるサブスキーマをJSONリテラル値"false"に設定すると、その単一の変数に対してユーザーエージェントデータが受け入れられなくなります。

インスタンスデータから解決できるテンプレート変数の場合、インスタンスデータが"hrefSchema"の適用可能なすべてのサブスキーマに対して有効である場合、その変数に対して入力データセットを事前に入力するために使用する必要があります。

データがインスタンスから事前に入力されている場合でも、"hrefSchema"内のその変数の検証スキーマは、インスタンスデータの場所に適用される検証スキーマと同じである必要はないことに注意してください。これにより、日時入力のスペルアウトされた月をサポートするなど、ユーザーエージェントデータの検証ルールを異ならせることができますが、ストレージには標準の日時形式を使用します。

入力が受け入れられた後、事前に入力されたインスタンスデータを上書きする可能性があり、結果として得られるデータセットは、"hrefSchema" の値に対して正常に検証されなければなりません。検証に失敗した場合、そのリンクは使用してはなりません。有効な場合、「URIテンプレート」セクションで説明されているプロセスが、この更新されたデータセットで続行されます。

6.6.2. headerSchema

[CREF2]"targetHints" と同様に、このキーワードは柔軟性と明確さのバランスを取ろうとする中で、実験とフィードバックを促すために、やや詳細が不明確な部分があります。

存在する場合、このプロパティは、プロトコル固有のリクエストヘッダーまたは同様の制御およびメタデータのスキーマです。このオブジェクトの値は、有効なJSON Schemaでなければなりません。プロトコルは "href" URIスキームによって決定されますが、リソースがそのようなプロトコルでアクセス可能であることが保証されているわけではないことに注意してください。スキーマはあくまで参考であり、対象リソースの動作はその存在によって制約されることはありません。

このキーワードの目的は、対象リソースのインタラクション機能を宣伝し、ユーザーエージェントとクライアントアプリケーションに、どのようなヘッダーとヘッダー値が役立つ可能性が高いかを示すことです。ユーザーエージェントとクライアントアプリケーションは、スキーマを使用して関連するヘッダーを検証することができますが、ヘッダーや値が欠落している場合、使用が禁止されていると仮定してはなりません。スキーマ作成者は "additionalProperties" を false に設定できますが、これは推奨されず、クライアントアプリケーションまたはユーザーエージェントがリクエストを行う際に追加のヘッダーを提供することを妨げてはなりません。

JSONデータモデルからヘッダーへの正確なマッピングはプロトコルに依存します。ただし、ほとんどの場合、このスキーマは "object" 型を指定する必要があり、プロパティ名は制御データフィールド名の小文字形式にする必要があります。"targetHints" と同様に、値は複数の値を許可するために、たとえ1つの値しか予期されていなくても、配列として記述する必要があります。

HTTPおよび類似のプロトコルでこのキーワードを使用するための詳細なガイダンスについては、「JSON Hyper-SchemaとHTTP」のセクションを参照してください。

"headerSchema" は、プロトコルがサポートする任意のリクエストメソッドまたはコマンドに適用できます。リクエストを生成する際、ユーザーエージェントとクライアントアプリケーションは、そのリクエストに関係のないヘッダーのスキーマを無視する必要があります。

6.6.3. 対象リソース表現の操作

JSON Hyper-Schemaでは、"targetSchema" は、対象リソースの表現に関する非権威的な記述を提供します。クライアントアプリケーションは、"targetSchema" を使用して、表現を置き換えたり変更したりするための入力を構成したり、パッチメディアタイプに基づいてパッチドキュメントを構築するためのベース表現として使用したりできます。

または、"targetSchema" が存在しない場合、またはクライアントアプリケーションが権威のある情報のみを使用することを好む場合、対象リソースと対話して、その表現構造を確認または検出することができます。

"targetSchema" は、レスポンスセマンティクスが対象リソースの表現であることを示す場合を除き、リンク操作レスポンスを記述することを意図していません。すべての場合において、レスポンス自体によって示されるスキーマが権威を持ちます。詳細な例については、「JSON Hyper-SchemaとHTTP」を参照してください。

6.6.4. 処理のためのデータの送信

"submissionSchema" および "submissionMediaType" キーワードは、対象リソースによって実装される処理関数のドメインを記述します。それ以外の場合、上記のように、送信スキーマとメディアタイプは、それらが関係しない操作では無視されます。

6.6.4.1. submissionMediaType

存在する場合、このプロパティは、クライアントアプリケーションとユーザーエージェントが "submissionSchema" で記述されたリクエストペイロードに使用する必要があるメディアタイプ形式を示します。

このキーワードを省略すると、application/json の値と同じ動作になります。

"submissionMediaType" と "submissionSchema" は、HTTP URIに限定されないことに注意してください。[CREF3]この記述は、例が最終的に配置される場所に移動する可能性があります。

6.6.4.2. submissionSchema

このプロパティには、"submissionMediaType" プロパティに従ってエンコードされ、処理のために対象リソースに送信されるドキュメントの許容される構造を定義するスキーマが含まれています。これは、対象リソースによって実装される処理関数のドメインを記述するものと見なすことができます。

これは、"targetSchema" プロパティとは異なる概念です。"targetSchema" は、"submissionSchema" とは異なり、ユーザーが送信したリクエストデータがリソースによって評価されるのに対し、対象情報リソース(PUTリクエストでリソースの内容を置き換える場合を含む)を記述します。"submissionSchema" は、対象表現の観点から必ずしも定義されないペイロードを持つリクエストでの使用を意図しています。

"submissionSchema" を省略すると、"true" の値と同じ動作になります。

7. 実装要件

大まかに言えば、適合実装は次の要件を満たします。これらの各要件は、個々のキーワードセクションとキーワードグループの概要で詳細に説明されています。

実装が "self"、"collection"、および "item" リンクを認識する方法に関する要件は、リンク関係タイプセクションで十分に説明されており、ここでは繰り返しません。

実装に必須の形式ではありませんが、テストスイートで使用される出力形式は、各リンクを使用できるようになる前に計算する必要がある内容を要約しています。

contextUri
コンテキストリソースの完全に解決されたURI(スキーム付き)。コンテキストがリソース全体ではなく、使用可能なフラグメント識別子の構文がある場合、URIにはフラグメントが含まれます。application/jsonにはそのような構文がないことに注意してください。
contextPointer
コンテキストリソースのインスタンス内の場所を示すJSONポインター。インスタンスメディアタイプがフラグメント識別子としてJSONポインターをサポートしている場合、このポインターは "contextUri" フィールドのフラグメントにエンコードされているものと同じになります。
rel
リンク関係タイプ。複数のリンク関係タイプがLDOに表示される場合、出力を作成する目的のために、単一のリンク関係タイプを持つが、それ以外は同一の複数のLDOとして扱われます。
targetUri
対象リソースの完全に解決されたURI(スキーム付き)。リンクが入力を受け入れる場合、これは入力が提供された後にのみ生成できます。
hrefInputTemplates
入力を受け入れるリンクの部分的に解決されたURI参照のリスト。リストの最初のエントリは、部分的に解決された "href" です。追加のエントリがある場合、最も近いものからスキーマのルートまで順序付けられた、部分的に解決された "base" 値です。入力に事前に入力されているテンプレート変数は、事前に入力された値を上書きできるため、この段階では解決されません。
hrefPrepopulatedInput
クライアント入力を受け入れる前に、ユーザーエージェントが入力メカニズムを事前に入力するために使用する必要があるデータセット。入力を受け入れる必要があるが、事前に入力するフィールドがない場合、これは空のオブジェクトになります。
attachmentPointer
リンクがアタッチされているインスタンス内の場所を示すJSONポインター。デフォルトでは、"contextUri" と "attachmentPointer" は同じですが、"contextUri" はLDOキーワードによって変更できますが、"attachmentPointer" は変更できません。

上記の情報の生成に関与しない他のLDOキーワードは、テストスイートの出力を作成する際に表示されるとおりに正確に含まれます。これらのフィールドは、特に該当する場合を除き、ここではさらに議論しません。

7.1. リンクの検出と検索

リンクを使用する前に、ハイパースキーマをインスタンスに適用し、適用可能で有効なすべてのリンクを見つけることで、リンクを検出する必要があります。有効なリンクを収集することに加えて、各LDOのURIテンプレートを解決するために必要なすべての"base" 値も、実装のURIテンプレート解決プロセスに最も役立つメカニズムを介して、LDOに関連付けられて配置する必要があることに注意してください。

実装は、アタッチメントポインターまたはコンテキストポインターのいずれかによってリンクを検索することをサポートする必要があります。検索を実行するか、両方のポインターが決定されたすべてのリンクのセットを提供することで、ユーザーエージェントが自分で検索を実装できるようにする必要があります。

コンテキストポインターで検索を実行する場合、同じ配列の要素にアタッチされているリンクは、アタッチされている配列要素と同じ順序で返される必要があります。

7.2. URIテンプレート

3つのハイパースキーマキーワードは、URIテンプレートです: "base"、"anchor"、および "href"。それぞれが個別にURI参照に解決され、次にアンカーまたはhrefのURI参照がベースに対して解決されます(ベース自体も必要に応じて以前のベースに対して解決され、それぞれが最初にURIテンプレートからURI参照に解決されました)。

3つのキーワードすべてが、インスタンスデータから変数を解決するために同じアルゴリズムを共有しており、"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:
        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の作成者は、このことを念頭に置き、正確な表現が重要な場合は、他のタイプ(文字列やブールなど)を使用する必要があります。数値が文字列の形式で入力として提供された場合は、入力として使用した文字列をSHOULD使用する必要があります。

7.3. LDOキーワードへのアクセスを提供する

特定のリンクについて、実装は、すべてのターゲット属性キーワードの値をユーザーエージェントに直接利用可能にする必要があります。実装は、各キーワードのセクションで説明されているように、この情報を使用するための追加のインターフェイスを提供する場合があります(MAY)。

特定のリンクについて、実装は、各入力スキーマキーワードの値をユーザーエージェントに直接利用可能にする必要があります。

URIテンプレート解決プロセスのカプセル化を促進するために、実装はURIの構築にのみ使用されるLDOキーワードを省略してもかまいません(MAY)。ただし、実装はリンク関係タイプへのアクセスを提供する必要があります(MUST)。

認識されないキーワードは、ユーザーエージェントで利用できるようにする必要があり(SHOULD)、それ以外の場合は無視する必要があります(MUST)。

7.4. リクエスト

ハイパースキーマの実装では、ターゲットリソースへの有効なリクエストを構築するために必要なすべての情報へのアクセスを提供する必要があります(SHOULD)。

LDOは、リンクに対する任意の操作を実行するために必要なすべての情報を表現できます。このセクションでは、インスタンスデータとクライアント入力の任意の組み合わせからリクエストを構築するために、ユーザーエージェントがどのハイパースキーマフィールドを調べる必要があるかについて説明します。ハイパースキーマの実装自体は、リクエストを構築および送信することが期待されていません。

入力受け入れのための「hrefSchema」を含む、ターゲットURI構築ルールは、すべての可能なリクエストで同一です。

本文ペイロードを運ばないリクエストは、追加のキーワードサポートを必要としません。

ターゲット表現をペイロードとして取るリクエストは、入力記述とペイロード検証のために「targetSchema」および「targetMediaType」キーワードをSHOULD使用します。プロトコルがメディアタイプ(パッチメディアタイプなど)によって変更された表現に基づくペイロードを取る操作を許可する場合、そのようなメディアタイプは、プロトコル固有の方法で「targetHints」を介して示す必要があります(SHOULD)。

ターゲットリソースの表現から派生していないペイロードを取るリクエストは、入力記述とペイロード検証のために「submissionSchema」および「submissionMediaType」キーワードをSHOULD使用します。ハイパーメディアで使用されるプロトコルは、一般に、リンクごとにそのような非表現操作を1つだけサポートします。

単一のハイパーメディアプロトコル操作を介して、任意の異なるリクエスト構造を持つ多数のアプリケーション操作をパイプするRPCシステムは、JSONハイパースキーマなどのハイパーメディア形式の範囲外です。

7.5. レスポンス

ハイパーメディア形式として、JSONハイパースキーマは、すべての有効なリクエストを作成するのに十分な詳細でリンクを記述することを含め、リソースを記述することに関心があります。これらのリクエストに対するすべての可能なレスポンスを直接記述することに関心はありません。

任意のハイパーメディアシステムと同様に、レスポンスは自己記述的であることが期待されます。ハイパースキーマのコンテキストでは、これは各レスポンスが独自のハイパースキーマにリンクする必要があることを意味します。ターゲットリソースの表現で構成されるレスポンスは、「targetSchema」および「targetMediaType」に対して有効であることが期待されますが、これらのキーワードはアドバイザリーのみであり、レスポンス自体と矛盾する場合は無視する必要があります。

エラーレスポンス、複雑なリダイレクト、処理ステータス表現などの他のレスポンスも、独自のスキーマにリンクし、適切なメディアタイプ(たとえば、エラーの場合は「application/problem+json」)を使用する必要があります。特定のエラーは、発生元ではなく、ハイパースキーマを認識していない仲介者によって生成されるため、スキーマをリンクしない場合があります。

ユーザーエージェントは、一般的な状況を処理するのに十分なプロトコルステータスコードとレスポンスメディアタイプを理解し、ドメイン固有のレスポンスを処理するためにクライアントアプリケーションに十分な情報を提供することが期待されます。

設計時にすべての可能なレスポンスとそのスキーマを静的にマッピングすることは、JSONハイパースキーマの範囲外ですが、ハイパースキーマに基づいて構築された他のJSONスキーマ語彙の範囲内である可能性があります(付録A.3を参照)。

7.6. ストリーミングパーサー

コンテキストに基づいてリンクを検出したり、リンクのコンテキストを使用してコレクションを識別したりするための要件は、ストリーミングパーサーで使用する場合に固有の課題を提示します。スキーマとインスタンスドキュメント全体を処理せずに、これらの要件を確実に満たすことはできません。

このような実装は、これまでに処理されたデータに基づいて非決定的な応答を返すことを選択できます(MAY)。このアプローチを提供する場合は、実装は応答の性質を明確にする必要があり(MUST)、すべてのデータが処理され、決定的な応答を返すことができるまでブロックして待機するオプションを提供する必要があります(MUST)。

8. JSONハイパースキーマとHTTP

JSONハイパースキーマはハイパーメディア形式であり、したがってプロトコルに依存しませんが、最も一般的な使用法はHTTPシステム、またはHTTPに明示的に類似したCoAPなどのプロトコルを使用するシステムであることが予想されます。

このセクションでは、各一般的なHTTPメソッドをリンクとともに使用する方法と、コレクションリソースがHTTP POSTに課す追加の制約についてガイダンスを提供します。さらに、HTTPレスポンスヘッダー値のヒントと、特定のリソースに関連する可能性のあるHTTPリクエストヘッダーの記述に関するガイダンスを提供します。

JSONスキーマコア仕様のセクション13では、ハイパーメディアシステムのインスタンスをスキーマにリンクする方法についてガイダンスを提供しています。これは、ネットワークアクセス可能なスキーマで行うことも、クライアントアプリケーション内に事前にパッケージ化されたスキーマを識別するだけでも行うことができます。JSONハイパースキーマは、このメカニズムを意図的に制約しませんが、可能な限りコア仕様に概説されている手法を使用することを推奨します(RECOMMENDED)。

8.1. ターゲットおよび関係タイプごとの1つのリンク

リンク記述オブジェクトは、HTTPメソッドなどのターゲットリソースでサポートされている操作を直接示しません。代わりに、操作は主にリンク関係タイプとURIスキームから推測する必要があります。

これは、ターゲットリソースとリンク関係タイプのペアごとに、スキーマ作成者は単一のLDOのみを定義する必要があることを意味します(SHOULD)。「targetHints」で「allow」を使用して、許可されている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」で定義されています。

RFC 5789に従い、HTTP PATCHのリクエスト構造は、「targetSchema」とリクエストメディアタイプ(「Accept-Patch」ヘッダーで伝えられます)の組み合わせによって決定されます。これは「targetHints」に含まれる場合があります。PATCHに適したメディアタイプは、ドキュメントへの変更を表現するための構文を定義します。これは、「targetSchema」で記述された表現に適用して、構文的に有効なリクエストペイロードのセットを決定できます。多くの場合、PATCHリクエストを検証する最も簡単な方法は、適用して、結果を通常の表現として検証することです。

8.3. HTTP POSTと「submission*」キーワード

JSONハイパースキーマは、ターゲットの表現を操作することに加えて、または代わりに、任意のデータを処理するリソースを許可します。この任意のデータは、「submissionSchema」および「submissionMediaType」キーワードによって記述されます。HTTPの場合、POSTメソッドはこのようなデータを処理する唯一のメソッドです。コレクションでPOSTを使用することに関する特定の規則がありますが、POSTリクエストのセマンティクスはHTTPではなくターゲットリソースによって定義されます。

プロトコルに依存しない「submission*」キーワード(HTTP以外の例についてはセクション9.3を参照)に加え、「Accept-Post」ヘッダーを使用して必要なメディアタイプを指定でき、「targetHints」フィールドを介してアドバタイズしてもよい。[CREF4]両方が使用された場合はどうなるのか?また、「submissionSchema」はサポートが必須である一方、「targetHints」は最大でSHOULDである。しかし、「targetHints」での「Accept-Post」の使用を禁止することは正しくないと思われる。

「Content-Location」が設定された201または200以外のPOSTへの成功応答には、同様にHTTPで定義されたセマンティクスはありません。すべてのHTTP応答と同様に、応答内のすべての表現は、その処理方法を示すために、それ自身のハイパースキーマにリンクする必要があります。付録A.2で述べたように、すべての可能な操作応答とハイパーリンクを関連付けることは、JSONハイパースキーマの範囲内ではありません。

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ヘッダーがある場合でも、それぞれに1つの値を持つ複数行のAllowヘッダーがある場合でも、またはそのような配置の任意の組み合わせでも、同じように表現されることに注意してください。一般にHTTPヘッダーで当てはまるように、カンマ区切りの値とヘッダーの複数の出現は、同じ方法で扱われます。

8.5. 「headerSchema」によるHTTP機能のアドバタイズ

スキーマは、進行中の作業「HTTPヘッダーフィールド値のJSONエンコーディング」で確立されたガイドラインに従うJSONシリアル化を記述するように作成する必要があります。そのドキュメントの例で示されているアプローチは、可能な限り、同様の構造の他のヘッダーにも適用する必要があります。

スキーマ作成者は、可能な場合はいつでも、次のタイプのHTTPヘッダーの利用可能な使用法を記述することが推奨されます。

キャッシュ制御や条件付きリクエストヘッダーなどのヘッダーは、通常、リソースではなく仲介によって実装されるため、記述するのに一般的に役立ちません。リソースは条件付きリクエストを使用するために必要な情報を提供する必要がありますが、そのようなヘッダーと関連する応答のランタイム処理はリソース固有ではありません。

8.6. コレクションによるリソースの作成

HTTP、またはHTTPに明示的に類似したCoAPなどのプロトコルを使用する場合、これは、作成される個々のリソースの表現をコレクションリソースにPOSTすることで行われます。コレクションおよびアイテムリソースを認識するプロセスについては、セクション6.2.3で説明されています。

8.7. コンテンツネゴシエーションとスキーマの進化

JSONハイパースキーマは、HTTPコンテンツネゴシエーションを容易にし、プロアクティブ戦略とリアクティブ戦略のハイブリッドを可能にします。上記で述べたように、ハイパースキーマには、「Accept」、「Accept-Charset」、「Accept-Language」などのHTTPヘッダーのスキーマを「headerSchema」キーワードを含めることができます。ユーザーエージェントまたはクライアントアプリケーションは、リアクティブなネゴシエーションプロセスを開始するための最初の要求を行う代わりに、サポートされている言語の列挙リストなど、このスキーマの情報を使用できます。

このようにして、これらのヘッダーを設定するプロアクティブなコンテンツネゴシエーション手法は、リアクティブネゴシエーションで代替案のリストを調べるのと同様に、どのような値が可能であるかに関するサーバー情報によって通知できます。

メディアタイプをメディアタイプパラメーターとして指定できるメディアタイプの場合、リクエストで送信されるか、「headerSchema」でアドバタイズされる「Accept」値には、ネゴシエートされた表現が準拠することが期待されるスキーマのURIを含めることができます。コンテンツネゴシエーションでのスキーマパラメーターの1つの可能な使用法は、リソースが時間の経過とともに複数の異なるスキーマバージョンに準拠している場合です。クライアントアプリケーションは、この方法で「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」リンクの2つのリンクを提供します。

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

これらは、関係タイプとテンプレート変数なしの「href」のみを持つ、最も単純な可能なリンクです。これらは次のように解決されます

「self」リンクのベースと「../api」hrefの両方での「api」の重複は、RFC 3986 URI参照解決アルゴリズムの癖によるものです。相対URI参照が一般的に適切に機能するためには、ベースURIに末尾のスラッシュを含める必要があります。「docs」hrefを持つ「about」リンクは、このドキュメントの他の例で使用されている相対参照の一般的なケースを示しています。

ただし、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. 個別に識別されたリソース

個々のものから始めて、システムに「もの」を追加しましょう

{
    "$id": "https://schema.example.com/thing",
    "$schema": "https://json-schema.dokyumento.jp/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
        }
    }
}
                    

私たちの「もの」には、サーバーによって割り当てられたIDがあり、「self」リンクを構築するために必要です。また、任意のタイプにできる「data」フィールドもあります。「$defs」セクションの理由は次の例で明らかになります。

「id」は検証スキーマでは必須ではありませんが、selfリンクでは必須であることに注意してください。これは理にかなっています。「もの」は、作成されてサーバーがIDを割り当てた場合にのみURIを持ちます。ただし、データフィールドのみを含むインスタンスでこのスキーマを使用できます。これにより、作成しようとしている「もの」インスタンスを検証できます。

入力としてIDを提供できる場合、特定のものに直接ジャンプできるエントリポイントスキーマへのリンクを追加しましょう。スペースを節約するために、新しいLDOのみが表示されます。「self」や「about」とは異なり、仮想的なものに関する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テンプレートを解決することと並行して使用することについて説明します。URIの構築またはペイロードの送信のいずれかが必要ですが、両方を同時に許可しないHTMLフォームとは異なり、JSONハイパースキーマは、同じリンク上の同じ操作に対して両方の種類の入力を記述できます。

「submissionSchema」および「submissionMediaType」フィールドは、ターゲットリソースの表現ではないペイロードを記述するためのものです。「http(s)://」URIで使用する場合、通常、HTTPの使用に関する付録で示されているように、POSTリクエストペイロードを指します。

この場合、RFC 6068、セクション3に従って、リソースを取得するための操作を提供しない「mailto:」URIを使用します。送信するメッセージを構築するためにのみ使用できます。取得可能、置換可能、または削除可能なターゲットリソースの概念がないため、「targetSchema」と「targetMediaType」は使用されません。表現以外のペイロードは、「submissionSchema」と「submissionMediaType」によって記述されます。

「submissionMediaType」を使用して、同じデータの2つの表現(HTMLとプレーンテキスト)を提供するmultipart/alternativeペイロード形式を示します。multipart/alternativeメッセージは順序付けられたシーケンス(最後の部分が最も優先される代替案)であるため、「submissionSchema」でシーケンスを配列としてモデル化します。各部分はそれ自体がメディアタイプを持つドキュメントであるため、配列内の各アイテムを文字列としてモデル化し、「contentMediaType」を使用して文字列内の形式を示します。

各部分に名前を関連付け、順序付けられていないmultipart/form-dataなどのメディアタイプは、配列ではなくJSONオブジェクトとしてモデル化する必要があることに注意してください。

一部の行は、このドキュメントの幅の制限に収まるように折り返されていることに注意してください。

{
    "$id": "https://schema.example.com/interesting-stuff",
    "$schema": "https://json-schema.dokyumento.jp/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パラメーターの場合、3つすべてが入力の解決方法の異なる方法を示しています

email
"templateRequired" にこの変数が存在するということは、テンプレートを使用するには解決が必要であることを意味します。「hrefSchema」でそれに割り当てられた "false" スキーマは、入力データセットからそれを除外するため、インスタンスから解決する必要があります。
タイトル
この変数に一致するインスタンスフィールドは必須であり、入力データにも許可されます。したがって、クライアント入力を受け入れる前に、インスタンス値を使用して入力データセットを事前設定します。クライアントアプリケーションは、インスタンス値をそのまま残すこともできます。「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*" キーワードに注目してください。これらは、さまざまな種類の入力をカバーする、3つの可能な "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 テンプレートの解決

リンクとは、コンテキストリソースからターゲットリソースへの型付き接続です。古いリンクのシリアル化では、"rel" と同様にリンク関係タイプを取得する "rev" キーワードがサポートされていましたが、セマンティクスが逆になります。これは長い間非推奨になっているため、JSON Hyper-Schema ではサポートされていません。代わりに、コンテキスト URI を変更する "anchor" の機能を使用して、リンクの方向を逆にすることができます。また、どちらも現在のリソースではない2つのリソース間のリンクを記述するためにも使用できます。

例として、IANA に登録された "up" 関係がありますが、"down" はありません。HTTP Link ヘッダーでは、"rev": "up" として "down" を実装できます。

最初に、HTTP でこれをどのように行うことができるかを見てみましょう。"self" リンクと、意味的に同一の2つのリンクを示します。1つは "rev": "up" を使用し、もう1つは "rel": "up" で "anchor" を使用しています(フォーマット上の制限により、行が折り返されています)。

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.dokyumento.jp/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 の両方で同じように評価されます。

使用されている2つの異なる種類の templatePointers に注意してください。"thisNodeId" は絶対 JSON ポインター "/id" にマップされ、"childId" は現在のアイテムの値を示す相対ポインター "0" にマップされます。絶対 JSON ポインターは、いかなる種類のワイルドカードもサポートしていないため、相対 JSON ポインターなしに「現在のアイテム」のような概念を指定する方法はありません。

9.5. コレクション

多くのシステムでは、個々のリソースがコレクションにグループ化されています。これらのコレクションは、多くの場合、サーバーが割り当てた識別子を持つ個々のアイテムリソースを作成する方法も提供します。

この例では、前のセクションで示した個々の thing スキーマを再利用します。便宜上、ここで繰り返します。次に紹介するコレクションスキーマを指す "targetSchema" 参照を持つ "collection" リンクを追加しました。

{
    "$id": "https://schema.example.com/thing",
    "$schema": "https://json-schema.dokyumento.jp/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.dokyumento.jp/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"}
        }
    ]
}
                    

以下は、単純な2要素コレクションインスタンスです。

{
    "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"
    }
]

                    

すべての場合において、コンテキスト URI は、フラグメントをサポートしないメディアタイプ application/json のインスタンスに対して表示されます。インスタンスのメディアタイプが、JSON ポインターフラグメントをサポートする application/instance+json である場合、コンテキスト URI には、コンテキストポインターフィールドと同じフラグメントが含まれます。application/json およびフラグメントのないその他のメディアタイプの場合、コンテキスト URI だけでなく、コンテキストポインターを検討することが非常に重要です。

3つの "self" リンクがあります。1つはコレクション用、もう1つは "elements" 配列内の各アイテム用です。アイテムの "self" リンクは、"$ref" で参照される個々の "thing" スキーマで定義されています。3つのリンクは、コンテキストまたは添付ポインターによって区別できます。セクション 9.5.2 で、コレクションの "self" リンクの "submissionSchema" を再検討します。

2つの "item" リンクがあります。"elements" 配列内の各アイテムに対して1つずつです。"self" リンクとは異なり、これらはコレクションスキーマでのみ定義されています。それらはそれぞれ、同じ添付ポインターを共有する対応する "self" リンクと同じターゲット URI を持ちます。ただし、それぞれ異なるコンテキストポインターを持っています。"self" リンクのコンテキストは "elements" のエントリですが、"item" リンクのコンテキストは、特定のアイテムに関係なく、常にコレクション全体です。

最後に、2つの "collection" リンクがあります。"elements" の各アイテムに対して1つずつです。個々のアイテムスキーマでは、これらはアイテムリソースをコンテキストとするリンクを生成します。コレクションスキーマから参照される場合、コンテキストは、"thing" 自体の個別のリソース URI ではなく、関連する "thing" の "elements" 配列内の場所です。

コレクションリンクは、関連するコレクション URI が1つしかないため、同一のターゲット 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 の issue #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" リンクを持つリソースはありません。したがって、最初の "thing" を作成するために "collection" リンクの送信キーワードを使用することはできません。ハイパースキーマはインスタンスに関して評価する必要があります。コレクションインスタンスの "elements" 配列が空であるため、コレクションリンクも提供できません。

ただし、エントリポイントリンクは空のコレクションに移動でき、ハイパースキーマに "item" リンクが存在することを利用して、それがコレクションであることを認識できます。"item" リンクのコンテキストはコレクションであるため、同じコンテキストを持つ "self" リンクを探し、作成操作の目的でコレクションとして扱うことができます。

おそらく、エントリポイントスキーマにおけるカスタムのリンク関係タイプは、正しいコレクションを見つけるのに十分でした。そのカスタムリンク関係タイプを認識するクライアントアプリケーションは、ターゲットがコレクションであるとすぐに仮定できることを知っているかもしれませんが、汎用的なユーザーエージェントはそうすることができません。例では "-collection" という接尾辞が付いていますが、汎用的なユーザーエージェントは、そのサブストリングがハイパーメディアリソースコレクションを示すのか、他の種類のコレクションを示すのかを知る方法はありません。

「self」リンクが正しいコレクションを指していると認識したら、その「submissionSchema」および/または「submissionMediaType」キーワードを使用して、アイテム作成操作を実行できます。[CREF8]これは、コレクションがフィルター処理されておらず、ページネーションされていない場合に完全に機能します。ただし、一般的には、作成されたリソースを含むコレクションに対してPOSTを行う必要があり、「self」リンクには、フィルター、ページネーション、またはその他のクエリパラメーターを含める必要があります。結果として得られるアイテムがフィルターに一致しない場合や、そのページに表示されない場合でも、そのような「self」リンクにPOSTすることは有効でしょうか?詳細については、GitHub issue #421を参照してください。 [CREF9]Hyper-SchemaのDraft-04では、コンテキストとしてインスタンスではなくスキーマを持つ「create」リンク関係が定義されていました。これはインスタンスベースのリンクモデルに適合せず、リンク関係タイプに操作名を誤って使用していました。ただし、スキーマからコレクションインスタンスへのより適切に設計されたリンクを定義することが、この問題を解決するための1つの可能なアプローチかもしれません。詳細については、GitHub issue #421を参照してください。

10. セキュリティに関する考慮事項

JSON Hyper-Schemaは、JSON Schemaコアの語彙を定義しており、そこに記載されているすべてのセキュリティ上の考慮事項に関与します。リンクシリアライズ形式として、RFC 8288 Web Linkingのセキュリティに関する考慮事項も適用されますが、適切な調整が必要です(例:「アンカー」はHTTP Linkヘッダー属性ではなくLDOキーワードとして扱われます)。

10.1. ターゲット属性

セクション 6.5で述べられているように、ターゲットリソースを記述するすべてのLDOキーワードは助言的なものであり、操作への応答でターゲットリソースによって提供される信頼できる情報の代わりに使用してはなりません。ターゲットリソースの応答には、信頼できる情報源である独自のハイパースキーマを示すべきです。

ターゲット応答のハイパースキーマが、現在のLDOが見つかったハイパースキーマと(「$id」によって)一致する場合、ターゲット属性は信頼できるとみなされるかもしれません。[CREF10]「$id」によるスプーフィングのリスクについて何かを追加する必要がありますが、仕様の他の部分で、リンクされたスキーマを常に再ダウンロードすることを推奨していないため、リスク軽減のオプションは不明確です。

ユーザーエージェントまたはクライアントアプリケーションは、「targetSchema」の値を使用して、リンクをたどった応答で受信したデータの解釈を支援してはなりません。これは「安全な」データを再解釈にさらすことになるからです。

データの解釈方法を選択する際には、サーバーによって提供されるタイプ情報(またはファイル名から推測される情報、またはその他の通常の方法)のみを考慮する必要があり、リンクの「targetMediaType」プロパティは使用してはなりません。ユーザーエージェントは、この情報を使用して、リンクの表現方法や表示場所(例:ホバーテキスト、新しいタブでの開き方)を決定できます。ユーザーエージェントがリンクを外部プログラムに渡すことを決定した場合、最初にデータが通常その外部プログラムに渡されるタイプのデータであることを検証する必要があります。

これは、「targetSchema」に対する予防措置と同様に、「安全な」データの再解釈を防ぐためです。

「targetHints」で伝達されるプロトコルメタデータ値は、信頼できるものとみなしてはなりません。メタデータ値に関する誤った仮定に基づいて適用される可能性のある、プロトコルによって定義されたセキュリティ上の考慮事項が適用されます。

プロトコルのセキュリティ上の考慮事項が直接適用されない場合でも、実装はリンクの「targetHints」の値と一致しない応答を処理する準備をする必要があります。

10.2. 「self」リンク

「self」というリンク関係がオブジェクトの完全な表現を示すために使用される場合、ターゲットURIが、「self」リンクを含むターゲットURIを含むリソース表現を要求するために使用されるURIと同等であるか、そのサブパスでない場合、ユーザーエージェントはその表現をターゲットURIで示されるリソースの信頼できる表現とみなすべきではありません。[CREF11]この段落の「サブパス」オプションが意図したものが何であるかは、もはや完全に明確ではありません。通常、コレクションのURIのサブパスであるターゲットURIを持つコレクション内の埋め込みアイテム表現の「self」リンクを信頼できるものと見なせるようにすることを意図していた可能性があります。ただし、これは単なる一般的な設計上の慣例であり、RFC 3986やURIの使用に関するその他のガイダンスに基づくものではないようです。詳細については、GitHub issue #485を参照してください。

11. 謝辞

JSON Schemaの初期ドラフトにご尽力いただいたGary Court氏、Francis Galiegue氏、Kris Zyp氏、Geraint Luff氏に感謝いたします。

ドキュメントへの提出とパッチに感謝いたします。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. and H. Andrews, "JSON Schema: A Media Type for Describing JSON Documents", Internet-Draft draft-handrews-json-schema-02, 2017年11月.
[json-schema-validation] Wright, A., Andrews, H. and G. Luff, "JSON Schema Validation: A Vocabulary for Structural Validation of JSON", Internet-Draft draft-handrews-json-schema-validation-02, 2017年11月.
[relative-json-pointer] Luff, G. and H. Andrews, "Relative JSON Pointers", Internet-Draft draft-handrews-relative-json-pointer-02, 2018年1月.
[RFC2119] Bradner, S., "Key words for use in RFCs to Indicate Requirement Levels", BCP 14, RFC 2119, DOI 10.17487/RFC2119, 1997年3月.
[RFC3986] Berners-Lee, T., Fielding, R. and L. Masinter, "Uniform Resource Identifier (URI): Generic Syntax", STD 66, RFC 3986, DOI 10.17487/RFC3986, 2005年1月.
[RFC4287] Nottingham, M. and R. Sayre, "The Atom Syndication Format", RFC 4287, DOI 10.17487/RFC4287, 2005年12月.
[RFC6570] Gregorio, J., Fielding, R., Hadley, M., Nottingham, M. and D. Orchard, "URI Template", RFC 6570, DOI 10.17487/RFC6570, 2012年3月.
[RFC6573] Amundsen, M., "The Item and Collection Link Relations", RFC 6573, DOI 10.17487/RFC6573, 2012年4月.
[RFC6901] Bryan, P., Zyp, K. and M. Nottingham, "JavaScript Object Notation (JSON) Pointer", RFC 6901, DOI 10.17487/RFC6901, 2013年4月.
[RFC8288] Nottingham, M., "Web Linking", RFC 8288, DOI 10.17487/RFC8288, 2017年10月.

12.2. 参考情報

[I-D.reschke-http-jfv] Reschke, J., "A JSON Encoding for HTTP Header Field Values", Internet-Draft draft-reschke-http-jfv-06, 2017年6月.
[RFC2046] Freed, N. and N. Borenstein, "Multipurpose Internet Mail Extensions (MIME) Part Two: Media Types", RFC 2046, DOI 10.17487/RFC2046, 1996年11月.
[RFC4151] Kindberg, T. and S. Hawke, "The 'tag' URI Scheme", RFC 4151, DOI 10.17487/RFC4151, 2005年10月.
[RFC5789] Dusseault, L. and J. Snell, "PATCH Method for HTTP", RFC 5789, DOI 10.17487/RFC5789, 2010年3月.
[RFC6068] Duerst, M., Masinter, L. and J. Zawinski, "The 'mailto' URI Scheme", RFC 6068, DOI 10.17487/RFC6068, 2010年10月.
[RFC7230] Fielding, R. and J. Reschke, "Hypertext Transfer Protocol (HTTP/1.1): Message Syntax and Routing", RFC 7230, DOI 10.17487/RFC7230, 2014年6月.
[RFC7231] Fielding, R. and J. Reschke, "Hypertext Transfer Protocol (HTTP/1.1): Semantics and Content", RFC 7231, DOI 10.17487/RFC7231, 2014年6月.
[RFC7807] Nottingham, M. and E. Wilde, "Problem Details for HTTP APIs", RFC 7807, DOI 10.17487/RFC7807, 2016年3月.

付録A. APIでのJSON Hyper-Schemaの使用

RESTアーキテクチャスタイルの制約に従うハイパーメディアAPIは、汎用的なユーザーエージェントの作成を可能にします。このようなユーザーエージェントは、アプリケーション固有の知識を持ちません。むしろ、定義済みのメディアタイプ、URIスキーム、プロトコル、およびリンク関係を理解し、それらを認識し、それらをサポートする既存のソフトウェアの使用を調整します。その後、クライアントアプリケーションはこのようなユーザーエージェントの上に構築でき、対話のメカニズムではなく、独自のセマンティクスとロジックに焦点を当てることができます。

ハイパースキーマは、一度に1つのリソースと関連するリンクのセットのみに関与します。Webブラウザーが一度に1つのHTMLページのみを操作し、そのページが「サイト」の一部として機能するかどうかという概念がないのと同様に、ハイパースキーマを認識するユーザーエージェントは一度に1つのリソースを操作し、そのリソースがAPIにどのように適合するかという概念を持っていません。

したがって、ハイパースキーマはAPI内での使用に適していますが、APIを独立した完全なエンティティとして記述することには適していません。リソースやリンクのスコープではなく、APIスコープで概念を記述する方法はなく、そのような記述はJSON Hyper-Schemaの境界外にあります。

A.1. ハイパースキーマによるリソースの進化

特定のJSON Hyper-Schemaは、単一の時点の単一のリソースで使用されるため、バージョン管理の固有の概念はありません。ただし、特定のリソースは、時間の経過とともに使用するスキーマを変更でき、これらのスキーマのURIを使用してバージョン情報を示すことができます。メディアタイプパラメーターでスキーマを示すことをサポートするメディアタイプで使用すると、これらのバージョン管理されたスキーマURIをコンテンツネゴシエーションで使用できます。

リソースは、複数のスキーマのインスタンスであることを示すことができ、これにより複数の互換性のあるバージョンを同時にサポートできます。その後、クライアントアプリケーションは、認識するハイパースキーマを利用し、新旧のバージョンを無視できます。

A.2. 応答とエラー

ハイパースキーマは一度に単一のリソースを表すため、リンクを使用して実行されるプロトコル操作に対するすべての可能な応答の列挙は提供しません。エラーを含む各応答は、それ自身の(場合によっては匿名の)リソースと見なされ、独自のハイパースキーマを識別し、オプションで、RFC 7807の「application/problem+json」などの適切なメディアタイプを使用して、ユーザーエージェントまたはクライアントアプリケーションが、プロトコル自身のステータスレポートを超えて提供される情報を解釈できるようにする必要があります。

A.3. APIのハイパースキーマの静的解析

インスタンスデータなしでハイパースキーマのセットを静的に分析して、ドキュメントやコードなどの出力を生成できます。ただし、検証とハイパースキーマの両方の完全な機能セットには、ランタイムインスタンスデータがないとアクセスできません。

これは、ハイパーメディアシステムに最大限のランタイム柔軟性を提供するための意図的な設計上の選択です。JSON Schemaをメディアタイプとして使用することで、静的解析やコンテンツ生成のための追加の語彙を確立できます。これらはこの仕様では扱われていません。また、個々のシステムでは、完全な設計時記述が目標である場合、静的に解析できるサブセットにその使用を制限することができます。[CREF12]APIドキュメントやその他の目的のための語彙が提案されており、貢献はhttps://github.com/json-schema-org/json-schema-vocabularies で歓迎されています。

付録B. 変更履歴

[CREF13]このセクションは、Internet-Draftステータスを離れる前に削除されます。

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

著者連絡先

ヘンリー・アンドリュース (編集者) メール: [email protected]
オースティン・ライト (編集者) メール: [email protected]