コアコンセプト
JSON:APIの仕様には多くの概念がありますが、そのすべてがここで文書化されているわけではありません。ただし、モジュールを有効に活用するために、仕様のすべての概念を完全に理解する必要は ありません。JSON:APIのドキュメントがどのように構造化されているか、モジュールがなぜある方法で物事を行うのかなど、より深く知りたい場合や、モジュールの設計についてもっと学びたい場合は、 jsonapi.org の仕様を読むことをお勧めします。
ドキュメントの構造
JSON:APIは、JSONドキュメントをどのように構造化すべきか、すべてのリクエストおよび/またはレスポンスボディにどのような情報を含めなければならないかについて、非常に明確な考え方を持っています。
すべてのリクエスト/レスポンスボディは、単一のJSONオブジェクトの下に置かなければなりません。
{
// your data here...
}
データ、つまり特定のリソース(複数可)に関する情報は、このトップレベルオブジェクト内の data と呼ばれる「メンバー」の下に置く必要があります。「メンバー」とは、JSONオブジェクト内の定義済みキーにすぎません。 data メンバーは、オブジェクト({})または 配列([])のいずれかになります。リソースを作成または更新する場合、これは常に 単一の アイテムを表す単一のオブジェクト({})です。複数のリソースの「コレクション」を取得する場合にのみ、このプロパティは配列になります。
{
"data": {
// Your resource data goes here.
}
}
その他のトップレベルメンバーには、 errors、 meta、 links、 included があります。このうち included が最も頻繁に使われるでしょうが、これについてはこのドキュメントの後半で説明します。
トップレベル構造の詳細については、 仕様 を参照してください。
data メンバーと included メンバーの中には、「リソースオブジェクト」または「リソース識別子オブジェクト」があります。「リソースオブジェクト」は、対象となるリソース(エンティティ)のコンテンツを表します。「リソース識別子オブジェクト」はデータベースの外部キーのようなもので、そのリソースのフィールドを一切含まずにリソースを識別します。 Drupalの用語で言えば、リソースオブジェクトは通常、単一のエンティティ(単一のノード、単一のタクソノミーターム、単一のユーザーなど)をJSONで表現したものです。同様にDrupalの用語で言えば、リソース識別子はエンティティを読み込むのに十分な情報、つまりタイプとIDだけであり、それ以外は何もありません。
すべてのリソースオブジェクトは 必ず 2つのメンバー、 type と id を含まなければなりません。唯一の例外は新しいエンティティを作成する場合で、この場合、Drupalが新しいリソースのIDを生成できるように id を省略できます。ただし、新しいエンティティを作成するときにクライアントアプリケーションがリソースのUUIDを提供することも完全に可能です。 すべての JSON:APIのIDはUUIDです。
type メンバーは 常に 必須です。typeメンバーの値は、適用可能な場合、エンティティタイプ名とバンドルから導出されます。エンティティリソースのタイプは常に entity_type--bundle というパターンに従います。例として、コアのarticle(記事)とbasic page(基本ページ)のノードタイプは、 node--article と node--page として表されます。
したがって、必須のプロパティやフィールドがないエンティティの場合、次のJSONで新しいエンティティを作成できます:
{
"data": {
"type": "node--my-bundle",
}
}
ただし、これだけではあまり役に立ちません。エンティティの実際の値を含める必要があります。そのために、JSON:APIには値を保持する2つのメンバー、 attributes と relationships があります。 attributes は基盤となるリソース固有の値を格納します。 relationships はシステム内の別のリソースに属する値です。Drupalの用語では、 relationships は通常、エンティティ参照によって格納される値を表します。Drupalのコアのarticleバンドルでは、これは uid プロパティかもしれません。これは、 uid プロパティが記事を執筆したユーザーへのエンティティ参照だからです。 attributes と relationships を含むドキュメントのボディは、次のようになります:
{
"data": {
"type": "node--my-bundle",
"id": "2ee9f0ef-1b25-4bbe-a00f-8649c68b1f7e",
"attributes": {
"title": "An Example"
},
"relationships": {
"uid": {
"data": {
"type": "user--user",
"id": "53bb14cc-544a-4cf2-88e8-e9cdd0b6948f"
}
}
}
}
}
ご覧のとおり、 uid プロパティは relationships メンバーの下にあります。メインのリソースと同様に、これは別個の独立したリソースであるため、 type と id メンバーも含みます。
uid には attributes も relationships もない ことに注意してください。これは、特別なクエリパラメータである include を使用して明示的に要求しない限り、JSON:APIがリレーションシップの内容を含めないためです。これについては、このドキュメントの後半で詳しく説明します(「リソースの取得(GET)」を参照)。
リソースオブジェクトの構造の詳細については、 仕様 を参照してください。
「仮想」リソース識別子
状況によっては、Drupalはリレーションシップが、データベースに保存されていないためJSON:APIで取得できないリソース(エンティティを参照先とするエンティティ参照)をターゲットにすることを許可します。「仮想」リソース識別子は、そのコンテキストに応じてさまざまな状況を示しますが、常に見つからないリソースに対応します。
Drupalコアにおける「仮想」リソース識別子の使用方法と意味
Drupalコアにおけるこの特殊なケースの最も注目すべき例は、 タクソノミータームの parent フィールドです。 このリレーションシップフィールドには、「仮想」タクソノミータームリソースのリソース識別子が含まれることがあります。この場合、「仮想」リソース識別子は <root> タクソノミータームを識別します。つまり、これは参照しているタームがそのボキャブラリの最上位にあることを示します。
仮想的なタクソノミータームの次のレスポンスドキュメントを例に挙げます:
{
"data": {
"type": "taxonomy_term--tags",
"id": "2ee9f0ef-1b25-4bbe-a00f-8649c68b1f7e",
"attributes": {
"name": "Politics"
},
"relationships": {
"parent": {
"data": [
{
"id": "virtual",
"type": "taxonomy_term--tags",
"meta": {
"links": {
"help": {
"href": "https://www.drupal.org/docs/8/modules/json-api/core-concepts#virtual",
"meta": {
"about": "Usage and meaning of the 'virtual' resource identifier."
}
}
}
}
}
]
}
}
}
}
この Term の parent リレーションシップ(エンティティ参照フィールド)のリソース識別子オブジェクトで、 id がUUIDではなく、 "virtual" であることに注目してください。これは、 トップレベルまたはルートレベルの Term が親として、保存されていない <root> ターム(target_id = 0) への参照を持つため必要です。
なぜ?
ルートタームが保存されておらず、 Term が複数の親を持つ可能性があることを考えると、重要な疑問は次のとおりです。次のような Term をどう区別するのか:
- 親が
Term3のみ([3])の場合? - 親が、保存されていないこのルート
TermとTerm3の両方([0, 3])の場合?
答えは、JSON:APIが "virtual" IDを使用せずに、保存されていないルートターム 0 を省略した場合、これら2つのケースを区別することができないということです!
「欠落」リソース識別子
Drupalは、削除されたリソースへのリレーションシップ(削除されたエンティティへの参照を持つエンティティ参照フィールド)を「クリーンアップ」しません。言い換えると、Drupalは「宙ぶらりんの」リレーションシップ(エンティティ参照)をそのまま残します。
JSON:APIは、そのような宙ぶらりんのリレーションシップに遭遇すると、「欠落(missing)」リソース識別子を使用します。
Drupalコアにおける「欠落」リソース識別子の使用方法と意味
「仮想」リソース識別子の例で説明した、 タクソノミータームの parent フィールドの例を続けます。特定のタクソノミータームが「Belgium」タクソノミータームを親に持っていたが、現在は「Belgium」タクソノミータームリソースが存在しなくなったと想像してください。おそらく、小国ベルギーが存在しなくなったためでしょう。すると、このリレーションシップフィールドには、「欠落」タクソノミータームリソースのリソース識別子が含まれることになります。
仮想的なタクソノミータームの次のレスポンスドキュメントを例に挙げます:
{
"data": {
"type": "taxonomy_term--tags",
"id": "2ee9f0ef-1b25-4bbe-a00f-8649c68b1f7e",
"attributes": {
"name": "Politics"
},
"relationships": {
"parent": {
"data": [
{
"id": "missing",
"type": "unknown",
"meta": {
"links": {
"help": {
"href": "https://www.drupal.org/docs/8/modules/json-api/core-concepts#missing",
"meta": {
"about": "Usage and meaning of the 'missing' resource identifier."
}
}
}
}
}
]
}
}
}
}
この Term の parent リレーションシップ(エンティティ参照フィールド)のリソース識別子オブジェクトで、 id がUUIDではなく、 "missing" であることに注目してください。それだけでなく、その type は unknown です(Drupalは参照エンティティのバンドルを保存せず、エンティティタイプのみを保存するため、JSON:APIのリソースタイプ名を決定することが不可能だからです)。
記事:Drupal ドキュメンテーションより。