インターネット技術タスクフォース H. アンドリュース、編集
インターネットドラフト Cloudflare, Inc.
対象ステータス:情報提供 A. ライト、編集
有効期限:2018年7月23日 2018年1月19日

JSONハイパースキーマ:JSONのハイパーメディア注釈のための語彙
draft-handrews-json-schema-hyperschema-01

概要

JSON Schemaは、様々な語彙を使用してJSONデータを記述するためのJSONベースのフォーマットです。このドキュメントでは、ハイパーリンクでJSONドキュメントに注釈を付けるための語彙を規定します。これらのハイパーリンクには、HTTPなどのハイパーメディア環境を介してリモートリソースを操作および対話する方法を記述する属性、およびインスタンス値に基づいてリンクが使用可能かどうかを判断する属性が含まれます。このドキュメントで説明されているハイパーリンクシリアル化フォーマットは、JSON Schemaとは独立して使用することもできます。

読者への注意

このドラフトの問題リストは、<https://github.com/json-schema-org/json-schema-spec/issues>にあります。

詳細については、<https://json-schema.dokyumento.jp/>を参照してください。

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

このメモのステータス

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

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

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

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

著作権表示

Copyright (c) 2018 IETF Trust およびドキュメント作成者として識別された個人。すべての権利を留保します。

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


目次

1. はじめに

JSONハイパースキーマは、ハイパーリンクと、HTTPなどのハイパーメディア環境を介してリモートJSONリソースを処理および操作するための指示でJSONドキュメントに注釈を付けるためのJSON Schema語彙です。

JSONハイパースキーマという用語は、これらのキーワードを使用するJSON Schemaを指すために使用されます。「ハイパースキーマ」という用語は、この仕様の範囲内でJSONハイパースキーマを指します。

リンクを指定するために導入された主要なメカニズムは、RFC 8288、セクション2 [RFC8288]で定義されている抽象リンクモデルのシリアル化であるリンク記述オブジェクト(LDO)です。

この仕様では、JSON Schemaコア [json-schema]およびJSON Schema検証 [json-schema-validation]仕様で定義されている概念、構文、および用語を使用します。読者はこれらの仕様書を所持していることが推奨されます。

2. 表記上の規則

このドキュメントのキーワード「MUST」、「MUST NOT」、「REQUIRED」、「SHALL」、「SHALL NOT」、「SHOULD」、「SHOULD NOT」、「RECOMMENDED」、「MAY」、「OPTIONAL」は、RFC 2119 [RFC2119]で説明されているように解釈されるものとします。

3. 概要

JSONハイパースキーマを使用すると、インスタンスデータからハイパーリンクを構築する方法を記述することにより、JSONドキュメントからハイパーメディアシステムを構築できます。

JSONインスタンスドキュメントと、そのインスタンスの有効なapplication/schema+jsonハイパースキーマの組み合わせは、単一のハイパーメディア表現として動作します。この分離を許可することで、ハイパースキーマベースのシステムは、プレーンJSONを期待するアプリケーションを適切にサポートし、ハイパースキーマ対応のアプリケーションおよびユーザーエージェントに完全なハイパーメディア機能を提供できます。

ユーザーエージェントは、application/schema+jsonメディアタイプと、ハイパースキーマ語彙の存在を示す「$schema」値を探すことで、ハイパースキーマの存在を検出できます。次に、ユーザーエージェントはJSONハイパースキーマの実装を使用して、スキーマとインスタンスドキュメントの組み合わせを、単一ドキュメントのハイパーメディア表現フォーマットと同じように、リソースの単一論理表現としてインターフェースを提供できます。

ハイパースキーマを使用すると、ワイヤ上の占有バイト数を減らし、リンク構築の負担をサーバーから各クライアントに分散できます。クライアントアプリケーションがそのリンクをリクエストしない限り、ユーザーエージェントはリンクを構築する必要はありません。JSONハイパースキーマは、サーバー側で、他のリンクシリアル化または表現フォーマットを実行時に生成したり、サーバープッシュの使用を容易にするために、リンクを事前にたどったりするためにも使用できます。

これは、IANAに登録されたリンク関係タイプ「self」を持つ単一のリンクを追加するハイパースキーマの例であり、「id」という名前の1つの既知のオブジェクトフィールドを持つインスタンスから構築されます。

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

インスタンスが{"id": 1234}で、RFC 3986セクション5.1 [RFC3986]に従ったそのベースURIが「https://api.example.com/」である場合、「https://api.example.com/thing/1234」が結果として得られるリンクのターゲットURIになります。

3.1. 用語

「スキーマ」、「インスタンス」、「メタスキーマ」という用語は、JSON Schemaコア仕様 [json-schema]で定義されているように解釈されるものとします。

「適用可能」および「添付」という用語は、JSON Schema検証仕様のセクション3 [json-schema-validation]で定義されているように解釈されるものとします。

「リンク」、「リンクコンテキスト」(または「コンテキスト」)、「リンクターゲット」(または「ターゲット」)、および「ターゲット属性」という用語は、RFC 8288のセクション2 [RFC8288]で定義されているように解釈されるものとします。

「ユーザーエージェント」という用語は、RFC 7230のセクション2.1 [RFC7230]で定義されているように解釈されるものとします。これは、特にHTTPクライアントではなく、ハイパーメディアシステムで使用される可能性のある任意のプロトコルに適用されるように一般化されています。

この仕様では、次の用語を定義します。

JSONハイパースキーマ
この仕様で定義されたキーワードを使用するJSON Schema。
ハイパースキーマ
このドキュメント内では、「ハイパースキーマ」という用語は常にJSONハイパースキーマを指します。
リンクの有効性
インスタンスの有効なリンクは、そのインスタンスに適用可能であり、リンク記述オブジェクトのキーワードによって課せられた要件に失敗しないリンクです。
汎用ユーザーエージェント
サポートする標準化されたリンク関係、メディアタイプ、URIスキーム、およびプロトコルの中から、任意のサーバーから任意のリソースと対話するために使用できるユーザーエージェント。ただし、特定のメディアタイプのプロファイルを特別に処理するように拡張できる場合があります。
クライアントアプリケーション
特定の目的でハイパーメディアシステムを使用するアプリケーション。このようなアプリケーションは、それ自体のユーザーエージェントである場合も、汎用ユーザーエージェントの上に構築されている場合もあります。クライアントアプリケーションは、アプリケーションのドメインに固有のリンク関係、メディアタイプ、URIスキーム、プロトコル、およびデータ構造の知識を使用してプログラムされます。
クライアント入力
ユーザーエージェントを通じて提供され、ほとんどの場合クライアントアプリケーションを通じて提供されるデータ。このようなデータは、ユーザーにインタラクティブにリクエストしたり、コマンドライン引数、構成ファイル、またはソースコードのハードコードされた値などの形式で、インタラクションの前に提供したりできます。
操作
ハイパーリンクの特定の用途。例えば、ネットワークリクエスト(プロトコルを示す "http://" のようなスキームを持つURIの場合)や、リンクに基づくアクションの実行("data:" URI からのデータの読み取り、"mailto:" リンクに基づく電子メールメッセージの作成など)。HTTPのような複数のメソッドをサポートするプロトコルの場合、各メソッドは同じリンクに対する個別の操作と見なされます。

3.2. 機能

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

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

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

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

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

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

リンク記述フォーマット [ldo] は、JSONスキーマなしで使用でき、このフォーマットの使用は、リンクを使用するデータ構造のスキーマとして規範的なリンク記述スキーマを参照することで宣言できます。規範的なリンク記述スキーマのURIは次のとおりです。<https://json-schema.dokyumento.jp/draft-07/links#>

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

5. スキーマキーワード

JSONスキーマ検証のセクション3 [json-schema-validation]で定義されているように、インスタンス内の位置に適用可能なすべてのスキーマからのハイパースキーマキーワードを、そのインスタンスで使用できます。

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

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

5.1. base

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

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

5.2. links

スキーマの "links" プロパティは、リンク記述オブジェクトをインスタンスに関連付けるために使用されます。このプロパティの値は配列である必要があり、配列内の項目は、以下で定義するようにリンク記述オブジェクトである必要があります。

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

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

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

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

リンク記述オブジェクトはオブジェクトである必要があり、"href" [href] プロパティと "rel" [rel] プロパティが存在する必要があります。各キーワードについては、このセクションで簡単に説明し、詳細な使用方法の説明と包括的な例については、ドキュメントの後半で説明します。

6.1. リンクコンテキスト

JSONハイパースキーマでは、リンクのコンテキストリソースは、デフォルトでは、それが添付されているサブインスタンス(JSONスキーマ検証仕様のセクション3 [json-schema-validation]で定義)です。これは多くの場合、インスタンスドキュメント全体ではありません。このデフォルトのコンテキストは、このセクションのキーワードを使用して変更できます。

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

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

6.1.1. anchor

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

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

6.1.2. anchorPointer

このプロパティは、リンクのコンテキストリソースと見なされるインスタンス内のポイントを変更します。プロパティの値は、JSON文字列表現形式の有効なJSONポインター、またはデフォルトのコンテキストに対して評価される有効な相対JSONポインター [relative-json-pointer]である必要があります。

既知のURIを持つ代替コンテキストは、"anchor" [anchor]キーワードで設定するのが最適ですが、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 [RFC4287]で最初に定義されたように、"self" リンクは、ターゲットURIがリンクコンテキストと同等のリソースを識別することを示します。JSONハイパースキーマでは、"self" リンクはインスタンスから解決可能である必要があり、したがって "hrefSchema" は存在してはなりません。

ハイパースキーマの作成者は、"self" リンクに使用に必要なすべてのインスタンスデータが含まれていることを保証するために "templateRequired" を使用する必要があります。

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

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

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

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

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

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

6.2.4. 拡張関係タイプの使用

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

拡張関係タイプの URI は、使用可能なスキームを使用している場合でも、参照可能である必要はありません。

6.3. リンクターゲット

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

6.3.1. href

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

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

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

このセクションのキーワードは、ハイパースキーマに関わるすべての URI テンプレート("base"、"anchor"、"href")を解決するときに使用されます。完全なテンプレート解決アルゴリズムについては、URI テンプレート [uriTemplating] セクションを参照してください。

"base" テンプレートを解決する場合、解決の開始点となるアタッチメントポイントは、"base" キーワード自体の添付点ではなく、解決が必要な "base" テンプレートを必要とする "href" または "anchor" キーワードのアタッチメントポイントであることに注意してください。

6.4.1. templatePointers

"templatePointers" リンク記述プロパティの値はオブジェクトである必要があります。オブジェクト内の各プロパティ値は、有効な JSON ポインター [RFC6901]、またはテンプレートが解決されるリンクのアタッチメントポイントに対して評価される有効な 相対 JSON ポインター [relative-json-pointer] である必要があります。

解決されるテンプレート内の変数名と一致するオブジェクト内の各プロパティ名について、そのプロパティの値は、その変数の変数解決の開始位置を調整します。解決されるテンプレート内のテンプレート変数名と一致しないプロパティは無視する必要があります。

6.4.2. templateRequired

このキーワードの値は配列である必要があり、要素は一意である必要があります。各要素は、パーセントエンコードなしで、リンクの URI テンプレート内の変数と一致する必要があります。URI テンプレート解決プロセス全体が完了した後、この配列に存在する変数が値を持たない場合、そのリンクは使用しないでください。

6.5. リンクターゲット属性

このセクションのすべてのプロパティは、アドバイザリ専用です。"title" や "description" などのキーワードは、主にリンクをユーザーに提示するために使用されますが、リンクのインタラクションや応答の性質を予測するキーワードは、信頼できるものとしてみなされてはなりません。ターゲットリソースのランタイム動作は、LDO のターゲット属性と矛盾する場合は常に尊重される必要があります。

6.5.1. title

このプロパティは、リンクのタイトルを定義します。値は文字列である必要があります。

ユーザーエージェントは、リンクをユーザーに表示するときにこのタイトルを使用できます。

6.5.2. description

このプロパティは、タイトルに存在する以上の追加情報を提供します。値は文字列である必要があります。タイトルは短い方が望ましいですが、説明はリンクの目的と使用法について詳しく説明するために使用できます。

ユーザーエージェントは、リンクをユーザーに表示するときにこの説明を使用できます。

6.5.3. targetMediaType

このプロパティの値は、このリソースをフェッチするときに返されると予想されるメディアタイプ RFC 2046 [RFC2046] を表します。このプロパティの値は、RFC 7231、セクション 5.3.2 - HTTP "Accept" ヘッダー [RFC7231] で定義されているのと同じパターンを使用して、メディア範囲になることもあります。

このプロパティは、他のリンクシリアル化形式の "type" プロパティに類似しています。ユーザーエージェントは、リンクがたどられる前に、ユーザーに提示するインターフェースを通知するためにこの情報を使用できますが、結果として得られるデータの解釈にこの情報を使用してはなりません。代わりに、ユーザーエージェントは、ランタイム解釈のために、応答によって指定されたメディアタイプを使用する必要があります。"targetMediaType" の誤用に関する詳細な調査については、「セキュリティに関する考慮事項」 [security] のセクションを参照してください。

コンテンツネゴシエーションをサポートするプロトコルの場合、実装では、"headerSchema" [headerSchema] のプロトコル固有の情報を使用して、可能なターゲットメディアタイプを記述することを選択できます。プロトコル固有の情報と "targetMediaType" の両方が存在する場合、"targetMediaType" の値はプロトコル固有の情報と互換性がある必要があり、コンテンツネゴシエーションがない場合に返されるメディアタイプを示す必要があります。

そのようなプロトコル固有の情報がない場合、または実装が関連するプロトコルを認識しない場合、値は "application/json" であるとみなされるべきです。

6.5.4. targetSchema

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

6.5.5. targetHints

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

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

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

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

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

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

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

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

6.6. リンク入力

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

6.6.1. hrefSchema

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

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

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

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

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

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

6.6.2. headerSchema

[CREF2]"targetHints" と同様に、このキーワードは、柔軟性と明確さのバランスを取るために、実験とフィードバックを奨励するために、やや十分に仕様が定められていません。

存在する場合、このプロパティはプロトコル固有のリクエストヘッダーまたは類似の制御およびメタデータのスキーマです。このオブジェクトの値は、有効な JSON スキーマである必要があります。プロトコルは "href" URI スキームによって決定されますが、リソースがそのようなプロトコルを介してアクセスできるとは限りません。スキーマはアドバイザリ専用です。ターゲットリソースの動作は、その存在によって制約されません。

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

JSON データモデルからヘッダーへの正確なマッピングは、プロトコルに依存します。ただし、ほとんどの場合、このスキーマでは「object」の型を指定する必要があり、プロパティ名は制御データフィールド名の小文字形式である必要があります。HTTP および類似のプロトコルでこのキーワードを使用するための詳細なガイダンスについては、「JSON ハイパースキーマと HTTP」 [HTTP] セクションを参照してください。

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

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

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

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

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

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

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

6.6.4.1. submissionMediaType

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

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

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

6.6.4.2. submissionSchema

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

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

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

7. 実装要件

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

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

実装の必須フォーマットではありませんが、テストスイートで使用される出力フォーマットは、各リンクを使用する前に計算する必要があるものを要約しています。

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

上記の情報を生成する際に含まれない他の LDO キーワードは、テストスイートの出力を作成するときに表示されるとおりに正確に含まれます。これらのフィールドは、特に関連性がない限り、ここではさらに説明しません。

7.1. リンクの検出と検索

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

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

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

7.2. URIテンプレート

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

3つのキーワードすべてが、インスタンスデータから変数を解決するために同じアルゴリズムを共有しており、"templatePointers" および "templateRequired" キーワードを利用します。"href" を解決する場合、絶対URIへの解決に必要な "href" と "base" テンプレートの両方で、アルゴリズムは "hrefSchema" キーワードに基づいてユーザー入力をオプションで受け入れるように変更されます。

各URIテンプレート(T)について、次の疑似コードは、TをURI参照(R)に解決するためのアルゴリズムを記述します。このアルゴリズムの目的のために

このアルゴリズムは、最初に "href" または "anchor" のいずれかに適用し、次いで必要に応じて後続の各 "base" に適用する必要があります。テンプレートが完全なURIまたはURI参照に解決されるかどうかを常に判断できるとは限らないため、順序が重要です。

英語では、高レベルのアルゴリズムは次のとおりです。

  1. インスタンスからテンプレート変数データを設定します
  2. 入力が必要な場合は、入力を受け入れます
  3. 必要なすべての変数に値があることを確認します
  4. 値を文字列にエンコードし、テンプレートに入力します

これは、疑似コードとしての高レベルのアルゴリズムです。"T" は、LDO 内の "href" または "anchor"、または包含スキーマ内の "base" から取得されます。各ステップの疑似コードが続きます。"initialTemplateKeyword" は、2つのうちのどちらがプロセスを開始したかを示します("base" は、これらのキーワードのいずれかを解決するために常に順番に解決されるため)。

templateData = populateDataFromInstance(T, ldo, instance)

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

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

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

                    

7.2.1. インスタンスからのテンプレートデータの設定

このステップでは、変数値をインスタンス内のさまざまな場所で検索します。各変数について

  1. 変数がそのキーワードの値に表示される場合は、"templatePointers" を使用して値を見つけます
  2. それ以外の場合は、リンクがアタッチされているインスタンス内の場所で、変数に一致するプロパティ名を検索します
  3. いずれの場合も、その場所に値がある場合は、テンプレート解決データセットに入れます

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

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

                        

7.2.2. テンプレートデータ用の入力を受け入れる

このステップは、いくつかのケースをサポートする必要があるため、比較的複雑です。一部の変数は入力を禁止し、一部の変数は入力を許可します。一部には入力インターフェースに表示する必要のある初期値があり、一部にはありません。

  1. 入力できる変数を決定します
  2. テンプレート解決データセットに値がある場合は、入力データセットを事前に入力します
  3. 入力を受け入れます(Webフォームを表示する、コールバックを作成するなど)
  4. 入力データセット(テンプレート解決データセットではない)を検証します
  5. 入力値をテンプレート解決データセットに入れ、既存の値を上書きします

"InputForm" は、適切な種類の入力メカニズムを表します。これは、リテラルのWebフォームである場合もあれば、特定のフィールドとデータ型を受け入れるコールバック関数などの、よりプログラム的な構造である場合もあります。この場合、必要に応じて初期値が与えられます。

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

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

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

inputData = form.acceptInput()

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

return inputData:

                        

7.2.3. データを文字列としてエンコードする

このセクションは簡単で、リテラルを文字列としての名前に変換し、数値を最も明白な方法で文字列に変換し、必要に応じてURIで使用するためにパーセントエンコードします。

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

                        

一部のソフトウェア環境では、数値の元のJSON表現は利用できません(1.0と1の違いを区別する方法はありません)。そのため、妥当な表現を使用する必要があります。スキーマとAPIの作成者はこれを念頭に置き、正確な表現が重要な場合は、他の型(文字列やブールなど)を使用する必要があります。数値が文字列の形式で入力として提供された場合、入力として使用された文字列を使用する必要があります。

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

特定のリンクについて、実装は全てのターゲット属性キーワードの値をユーザーエージェントが直接利用できるようにしなければなりません(MUST)。実装は、各キーワードのセクションで説明されているように、この情報を使用するための追加のインターフェースを提供してもよい(MAY)。

特定のリンクについて、実装は各入力スキーマキーワードの値をユーザーエージェントが直接利用できるようにしなければなりません(MUST)。

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

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

7.4. リクエスト

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

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

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

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

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

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

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

7.5. レスポンス

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

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

エラーレスポンス、複雑なリダイレクト、処理ステータス表現を含むその他のレスポンスも、自身のスキーマにリンクし、適切なメディアタイプ(エラーの場合は"application/problem+json" [RFC7807]など)を使用する必要があります(SHOULD)。特定のエラーは、オリジンではなく、ハイパースキーマを認識していない中間者によって生成されたため、スキーマをリンクしない場合があります。

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

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

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

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

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

8. JSON Hyper-SchemaとHTTP

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

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

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

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

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

これは、各ターゲットリソースとリンク関係タイプのペアについて、スキーマ作成者は単一のLDOのみを定義する必要がある(SHOULD)ことを意味します。"targetHints"で"allow"を使用して、許可されているHTTPメソッドがマークされた異なるHTTPメソッドで関係タイプとターゲットペアを繰り返すことは可能ですが、これは推奨されず(NOT RECOMMENDED)、適合する実装で十分にサポートされない可能性があります。

各HTTPメソッドを使用するために必要なすべての情報は、このセクションで説明するように、単一のLDOで伝達できます。"targetHints"の"allow"フィールドは、サポートされている操作を示すためだけの意図であり、各操作を個別に定義するためのものではありません。

ただし、リソースは、たとえば、承認の失敗や、操作の可用性を制御する他のアプリケーション状態のために、実行時に常に操作を拒否する可能性があることに注意してください。

8.2. "targetSchema"とHTTP

"targetSchema"はリンクのターゲット側のリソースを記述し、"targetMediaType"はそのリソースのメディアタイプを定義します。HTTPリンクでは、"headerSchema"を使用して、複数のメディアタイプまたはメディアーレンジをサポートできる"Accept"リクエストヘッダーで使用する有効な値を記述することもできます。ターゲットメディアタイプを示す両方の方法が存在する場合、"targetMediaType"はデフォルトの表現メディアタイプを示す必要があり(SHOULD)、"headerSchema"の"accept"のスキーマには、デフォルトだけでなく、リクエスト可能な代替メディアタイプまたはメディアーレンジを含める必要があります(SHOULD)。

多くのHTTPメソッドのセマンティクスはターゲットリソースに関して定義されているため、"targetSchema"はいくつかのHTTPメソッドのリクエストまたはレスポンスに使用されます。特に、"targetSchema"は、HTTP GETに対するレスポンス、または"Content-Location"ヘッダーがリクエストURIに等しいレスポンスについて、クライアントアプリケーションが期待できるものを提案し、HTTP PUTリクエストでリソースを置き換える場合にクライアントアプリケーションが送信する必要があるものを提案します。これらの相関関係は、RFC 7231、セクション4.3.1 - "GET"、セクション4.3.4 "PUT"、およびセクション3.1.4.2、"Content-Location" [RFC7231]によって定義されています。

RFC 5789 [RFC5789]に従い、HTTP PATCHのリクエスト構造は、"targetSchema"とリクエストメディアタイプの組み合わせによって決定されます。これは、"Accept-Patch"ヘッダーによって伝達され、"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"はサポートする必要がある(MUST)のに対し、"targetHints"は最大でもサポートする必要がある(SHOULD)だけです。しかし、"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エンコーディング」[I-D.reschke-http-jfv]によって確立されたガイドラインに従うべきです。そのドキュメントの例に示されているアプローチは、可能な限り、他の同様に構造化されたヘッダーにも適用されるべきです。

すべての可能なHTTPメソッドレスポンスのヘッダーはすべて「headerSchema」を共有します。特に、HEADレスポンスに表示されるヘッダーと、OPTIONSレスポンスに表示されるヘッダーの両方が表示される可能性があります。「headerSchema」内では、どのメソッドレスポンスにどのヘッダーが含まれているかについての区別はされません。

スキーマの作成者は、適用可能な場合は常に、以下のタイプのHTTPヘッダーの値に関するヒントを提供することを推奨します。

一般的に、異なる時点で異なる値を持つ可能性が高いヘッダーは、「targetHints」に含めるべきではありません。

8.5. 「headerSchema」によるHTTP機能の広告

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

スキーマの作成者は、適用可能な場合は常に、以下のタイプのHTTPヘッダーの利用可能な使用法を記述することを推奨します。

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

8.6. コレクションを介したリソースの作成

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

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

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

このようにして、これらのヘッダーを設定するという積極的なコンテンツネゴシエーション手法は、受動的なネゴシエーションで代替案のリストを調べるのと同様に、何が可能かについてのサーバー情報によって通知できます。

メディアタイプパラメーターとしてスキーマを指定できるメディアタイプの場合、リクエストで送信される「Accept」値または「headerSchema」でアドバタイズされる値には、ネゴシエートされた表現が準拠することが期待されるスキーマのURIを含めることができます。コンテンツネゴシエーションにおけるスキーマパラメーターの考えられる用途の1つは、リソースが時間の経過とともに複数の異なるスキーマバージョンに準拠している場合です。クライアントアプリケーションは、この方法で「Accept」ヘッダーで理解しているバージョンを示すことができます。

9.

このセクションでは、URIとJSONポインターを構築するキーワードの使用方法を示します。結果はテストスイートで使用される形式で表示されます。[CREF6]それを投稿してリンクする必要がありますが、この段階でレビューしている皆様にはかなり自明であるはずです。

他のほとんどのキーワードは、単純である(「title」と「description」)、特定の種類の入力、リクエスト、またはレスポンスに検証を適用する、またはプロトコル固有の動作を持つものです。HTTPの使用法を示す例は、付録[HTTP]で利用可能です。

9.1. エントリポイントリンク、テンプレートなし

この例では、https://example.comというドキュメント化されたエントリポイントURIを持つ例のAPIを想定します。これは、スキーマへのリンクを持つ空のJSONオブジェクトです。ここで、エントリポイント自体にはデータがなく、初期リンクセットを提供するためだけに存在します。

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

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

                    

リンクされたハイパースキーマは、APIのベースURIを定義し、APIドキュメントへの「about」リンクと、これがベースURIのスキーマであることを示す「self」リンクの2つのリンクを提供します。この場合、ベースURIはエントリポイントURIでもあります。

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

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

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

アタッチメントポインターはルートポインターです(インスタンスの空のオブジェクトで唯一の可能性)。コンテキストURIはデフォルトであり、リクエストされたドキュメントです。application/jsonはフラグメントを許可しないため、コンテキストポインターはコンテキストを完全に記述するために必要です。そのデフォルトの動作は、アタッチメントポインターと同じになることです。

9.2. 個別に識別されたリソース

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

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

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

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

入力としてIDを提供できる場合に、特定のthingに直接ジャンプできるエントリポイントスキーマへのリンクを追加しましょう。スペースを節約するために、新しいLDOのみが表示されます。「self」と「about」とは異なり、仮説的なthingに関するIANA登録された関係はないため、「tag:」URIスキーム[RFC4151]を使用して拡張関係が定義されます。

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

ここでの「href」値は同じですが、その他はすべて異なります。インスタンスは空のオブジェクトであるため、「id」はインスタンスデータから解決できないことを思い出してください。代わりに、クライアント入力として必要です。このLDOは「templateRequired」を使用することもできますが、「hrefSchema」で「required」を使用すると厳密には必要ありません。「hrefSchema」で「id」を必須としてマークせずに「templateRequired」を提供すると、クライアント入力がこのリンクを解決するための唯一の可能なソースであるため、エラーが発生します。

9.3. ペイロードの送信とURI入力の受け入れ

この例では、表現以外の入力に「submission」フィールドを使用することと、入力でURIテンプレートを解決することと並行して使用することについて説明します。URIを構築するかペイロードを送信する必要があるHTMLフォームとは異なり、両方を同時に許可しない場合、JSONハイパースキーマは同じリンク上の同じ操作に対して両方の種類の入力を記述できます。

「submissionSchema」フィールドと「submissionMediaType」フィールドは、ターゲットリソースの表現ではないペイロードを記述するためのものです。「http(s)://」URIで使用する場合、一般にHTTPの使用に関する付録[HTTP]で見られるように、POSTリクエストペイロードを参照します。

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

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

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

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

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

URIパラメーターについては、それぞれが入力の解決方法が異なる3つの方法を示しています。

email
この変数が「templateRequired」に存在するということは、テンプレートを使用するには解決する必要があることを意味します。「hrefSchema」で割り当てられた「false」スキーマは入力データセットから除外されるため、インスタンスから解決する必要があります。
title
この変数に一致するインスタンスフィールドは必須であり、入力データでも許可されています。したがって、インスタンス値は、クライアント入力を受け入れる前に、入力データセットを事前に入力するために使用されます。クライアントアプリケーションは、インスタンス値をそのまま残すことを選択できます。このフィールドは「hrefSchema」で必須であるため、クライアントアプリケーションは削除できません(空の文字列に設定することはできます)。
cc
メインスキーマでこれに設定された「false」スキーマは、このフィールドがインスタンス値を持つことを防ぎます。それが存在する場合、クライアント入力からのものである必要があります。「hrefSchema」では必須ではないため、まったく使用されない可能性があります。

したがって、「https://api.example.com/stuff」から取得した次のインスタンスを考えると

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

クライアントアプリケーションに入力を求める前に、次のようにリンクを部分的に解決できます。

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

「targetUri」の代わりに「href*」キーワードがあることに注意してください。これらは、さまざまな種類の入力をカバーする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=あなたの%20作品&[email protected]"

9.4. "anchor"、"base"、および URI テンプレートの解決

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

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

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

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

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

                    

"rel=up" リンクのターゲット URI が "rel=self" リンクと同一であることに注意してください。また、"anchor" (リンクのコンテキストを識別)が子 URI に設定されています。この種の逆方向のリンクは、"self" リンクも存在する場合、ツールによって簡単に検出できます。

上記のレスポンスのインスタンスに適用される次のハイパースキーマは、同じ "self" リンクと "anchor" 付きの "up" リンクを生成します。また、テンプレート化された "base" URI と、"templatePointers" での絶対 JSON ポインタと相対 JSON ポインタの両方の使用を示しています。

{
    "$id": "https://schema.example.com/tree-node",
    "$schema": "https://json-schema.dokyumento.jp/draft-07/hyper-schema#",
    "base": "trees/{treeId}/",
    "properties": {
        "id": {"type": "integer"},
        "treeId": {"type": "integer"},
        "childIds": {
            "type": "array",
            "items": {
                "type": "integer",
                "links": [
                    {
                        "anchor": "nodes/{thisNodeId}",
                        "rel": "up",
                        "href": "nodes/{childId}",
                        "templatePointers": {
                            "thisNodeId": "/id",
                            "childId": "0"
                        }
                    }
                ]
            }
        }
    },
    "links": [
        {
            "rel": "self",
            "href": "nodes/{id}"
        }
    ]
}
                    

"base" テンプレートは、ターゲット ("href") とコンテキスト ("anchor") URI の両方に対して同一に評価されます。

使用されている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-07/hyper-schema#",
    "base": "https://api.example.com/",
    "type": "object",
    "required": ["data"],
    "properties": {
        "id": {"$ref": "#/definitions/id"},
        "data": true
    },
    "links": [
        {
            "rel": "self",
            "href": "things/{id}",
            "templateRequired": ["id"],
            "targetSchema": {"$ref": "#"}
        }, {
            "rel": "collection",
            "href": "/things",
            "targetSchema": {"$ref": "thing-collection#"},
            "submissionSchema": {"$ref": "#"}
        }
    ],
    "definitions": {
        "id": {
            "type": "integer",
            "minimum": 1,
            "readOnly": true
        }
    }
}
                    

"collection" リンクはすべての項目で同じであるため、URI テンプレート変数はありません。"submissionSchema" は項目自体のスキーマです。セクション 6.2.3で説明されているように、"collection" リンクが送信メカニズム(HTTP の POST)をサポートする場合は、項目作成セマンティクスを実装する必要があります。したがって、"submissionSchema" は、このリンクを介して "thing" を作成するためのスキーマです。

次に、"thing" のコレクションを記述します。このスキーマは、各項目の表現が個々の "thing" の表現と同一であるコレクションを記述します。多くのコレクション表現には項目表現のサブセットのみが含まれていますが、この例では、関連するスキーマの数を最小限に抑えるために全体を使用します。実際のコレクション項目は、オブジェクト内の配列として表示されます。次の例でオブジェクトにフィールドを追加します。

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

以下に、単純な2要素のコレクションインスタンスを示します

{
    "elements": [
        {"id": 12345, "data": {}},
        {"id": 67890, "data": {}}
    ]
}
                    

以下に、参照されている個々の "thing" スキーマで定義されているものを含め、このインスタンスに適用されるすべてのリンクを示します

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

                    

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

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

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

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

コレクションリンクは、関連するコレクション URI が1つしかないため、同一のターゲット URI を持ちます。構築されたリンクの完全なセットの一部として両方のリンクを計算することは有用ではないように思えるかもしれませんが、必要に応じてリンクを構築する場合、この配置は、処理している "elements" エントリに関係なく、近くに "collection" リンク定義があることを意味します。

9.5.1. ページネーション

ここでは、コレクションにページネーションを追加します。現在、次、および前のページに関する情報を保持する "meta" セクションがあります。スキーマのほとんどは前のセクションと同じであり、省略されています。新しいフィールドと、新しい(またはメインの "self" リンクの場合)変更されたリンクのみが完全に表示されます。

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

"self" リンクには、入力でページを選択できるようにするコレクションへの汎用リンクではなく、正確な表現を生成したページネーションクエリが含まれていることに注意してください。

このインスタンスを考えると

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

以下に、前の例で表示されなかったか、ページネーションが追加されて変更された、このインスタンスに適用されるすべてのリンクを示します。

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

最初のページを見ているため、出力に "prev" リンクがないことに注意してください。"meta" の下に "prev" フィールドがないことと、"prev" リンクの "templateRequired" 値は、この特定のインスタンスではリンクが使用できないことを意味します。

[CREF7]個々の "thing" スキーマの "collection" リンクからのリンクでページネーションがどのように機能するかは明確ではありません。技術的には、項目からページネーションまたはフィルタリングされたコレクションへのリンクは、リンクコンテキストである項目(この場合は "thing")を含むページ/フィルタに移動する必要があります。詳細については、GitHub issue #421 を参照してください。

クライアントアプリケーションが特定のページに直接ジャンプできるようにするために、エントリポイントスキーマ(セクション 9.1)へのこのコレクションのリンクを追加しましょう。ページネーション入力を追加します。エントリポイントスキーマはリンクのみで構成されているため、新しく追加されたリンクのみを示します

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

これで、ページネーションパラメータが入力として受け入れられていることがわかります。これにより、コレクション内の任意のページにジャンプできます。汎用 "collection" リンクは、エントリポイントやその他のリソースではなく、コンテキストとして項目でのみ使用できるため、リンク関係タイプはカスタムです。

9.5.2. 最初の項目の作成

"thing" がない場合、関連する "collection" リンクを持つリソースはありません。したがって、最初の "thing" を作成するために "collection" リンクの送信キーワードを使用することはできません。ハイパースキーマはインスタンスに関して評価する必要があります。コレクションインスタンス内の "elements" 配列が空であるため、コレクションリンクを提供することもできません。

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

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

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

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

JSON Hyper-Schema は JSON Schema コアの語彙を定義し、そこに記載されているすべてのセキュリティ上の考慮事項に関係します。リンクシリアライゼーション形式として、RFC 8288 Web Linking [RFC8288] のセキュリティ上の考慮事項も適用されます(たとえば、"anchor" が HTTP Link ヘッダー属性ではなく LDO キーワードであるなど、適切な調整を加えたもの)。

10.1. ターゲット属性

セクション 6.5で述べたように、ターゲットリソースを記述するすべての LDO キーワードは推奨事項であり、操作への応答としてターゲットリソースによって提供される信頼できる情報の代わりに使用してはなりません。ターゲットリソースの応答では、信頼できるハイパースキーマを示す必要があります。

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

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

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

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

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

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

10.2. "self" リンク

"self" のリンク関係がオブジェクトの完全な表現を示すために使用される場合、ターゲット URI が、"self" リンクを含むリソース表現を要求するために使用された URI と同じであるか、そのサブパスでない場合、ユーザーエージェントはその表現を、ターゲット URI で示されるリソースの信頼できる表現であると見なすべきではありません(SHOULD NOT)。[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. 規範的な参考文献

[RFC2119] Bradner, S., "RFC における要求レベルを示すためのキーワード", BCP 14, RFC 2119, DOI 10.17487/RFC2119, 1997年3月。
[RFC3986] Berners-Lee, T., Fielding, R. and L. Masinter, "Uniform Resource Identifier (URI): 一般構文", STD 66, RFC 3986, DOI 10.17487/RFC3986, 2005年1月。
[RFC4287] Nottingham, M. and R. Sayre, "Atom Syndication Format", RFC 4287, DOI 10.17487/RFC4287, 2005年12月。
[RFC6570] Gregorio, J., Fielding, R., Hadley, M., Nottingham, M. and 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. and M. Nottingham, "JavaScript Object Notation (JSON) ポインター", RFC 6901, DOI 10.17487/RFC6901, 2013年4月。
[RFC8288] Nottingham, M., "Web Linking", RFC 8288, DOI 10.17487/RFC8288, 2017年10月。
[relative-json-pointer] Luff, G. and H. Andrews, "相対JSONポインター", Internet-Draft draft-handrews-relative-json-pointer-01, 2018年1月。
[json-schema] Wright, A. and H. Andrews, "JSONドキュメントを記述するためのメディアタイプとしてのJSONスキーマ", Internet-Draft draft-handrews-json-schema-00, 2017年11月。
[json-schema-validation] Wright, A., Andrews, H. and G. Luff, "JSONの構造検証のためのボキャブラリーとしてのJSONスキーマ検証", Internet-Draft draft-handrews-json-schema-validation-00, 2017年11月。

12.2. 参考となる参考文献

[RFC2046] Freed, N. and N. Borenstein, "Multipurpose Internet Mail Extensions (MIME) Part Two: メディアタイプ", RFC 2046, DOI 10.17487/RFC2046, 1996年11月。
[RFC4151] Kindberg, T. and S. Hawke, "'tag' URIスキーム", RFC 4151, DOI 10.17487/RFC4151, 2005年10月。
[RFC5789] Dusseault, L. and J. Snell, "HTTPのPATCHメソッド", RFC 5789, DOI 10.17487/RFC5789, 2010年3月。
[RFC6068] Duerst, M., Masinter, L. and J. Zawinski, "'mailto' URIスキーム", RFC 6068, DOI 10.17487/RFC6068, 2010年10月。
[RFC7230] Fielding, R. and J. Reschke, "Hypertext Transfer Protocol (HTTP/1.1): メッセージ構文とルーティング", RFC 7230, DOI 10.17487/RFC7230, 2014年6月。
[RFC7231] Fielding, R. and J. Reschke, "Hypertext Transfer Protocol (HTTP/1.1): セマンティクスとコンテンツ", RFC 7231, DOI 10.17487/RFC7231, 2014年6月。
[RFC7807] Nottingham, M. and E. Wilde, "HTTP APIの問題詳細", RFC 7807, DOI 10.17487/RFC7807, 2016年3月。
[I-D.reschke-http-jfv] Reschke, J., "HTTPヘッダーフィールド値のJSONエンコーディング", Internet-Draft draft-reschke-http-jfv-06, 2017年6月。

付録A. APIにおけるJSONハイパースキーマの使用

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

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

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

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

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

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

A.2. 応答とエラー

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

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

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

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

付録B. 変更履歴

[CREF13]このセクションは、インターネットドラフトのステータスを離れる前に削除されます。

draft-handrews-json-schema-hyperschema-01

draft-handrews-json-schema-hyperschema-00

draft-wright-json-schema-hyperschema-01

draft-wright-json-schema-hyperschema-00

draft-luff-json-hyper-schema-00

著者のアドレス

Henry Andrews (編集者) Cloudflare, Inc. サンフランシスコ, CA 米国 メール: [email protected]
オースティン・ライト(編集者) メール: [メール保護]