コンテンツフラグメントと共に使用する AEM GraphQL API graphql-api-for-use-with-content-fragments
Adobe Experience Manager(AEM) のコンテンツフラグメントを AEM GraphQL API と共に使用してヘッドレスコンテンツ配信を実現する方法を説明します。
コンテンツフラグメントと共に使用する AEM GraphQL API は、オープンソースの標準 GraphQL API に大いに基づいています。
AEM の GraphQL API を使用すると、ヘッドレス CMS 実装の JavaScript クライアントにコンテンツフラグメントを効率的に配信できます。
- REST で API リクエストの反復を回避
- 特定の要件に限定された配信を確保
- 1 つの API クエリへの応答としてレンダリングに必要なものだけを一括配信
- AEM Commerce が、GraphQL 経由でコマースプラットフォームのデータを使用する。
- AEM コンテンツフラグメントが、AEM GraphQL API(標準の GraphQL に基づくカスタム実装)と連携して、アプリケーションで使用するための構造化コンテンツを配信する。
前提条件 prerequisites
GraphQL を使用しているお客様は、GraphQL インデックスパッケージ 1.0.5 を使用した AEM コンテンツフラグメントをインストールする必要があります。詳しくは、リリースノートを参照してください。
GraphQL API graphql-api
GraphQL とは次のことを意味します。
-
「…API のクエリ言語と、既存のデータを使用してこれらのクエリを満たすランタイムです。GraphQL は、API でデータの完全で理解可能な説明を提供します。必要なものと不要なものを正確に求める力をクライアントに提供し、API を時間の経過と共に発展させ、強力な開発者ツールを実現します」。
GraphQL.org を参照
-
「…柔軟な API レイヤー用のオープンな仕様。GraphQL を既存のバックエンドに重ね合わせ、これまでにない速さで製品を構築できます…」
Explore GraphQL を参照してください。
-
「…2012 年に Facebook 社内で開発されたデータクエリ言語および仕様です。その後、2015 年には公式にオープンソースとなりました。開発者の生産性を高め、転送データの量を最小限に抑えるために、REST ベースのアーキテクチャに代わる手段を提供します。GraphQL は、あらゆる規模の数百の組織により実稼働環境で使用されています…」
GraphQL Foundation を参照してください。
GraphQL API について詳しくは、(多くのリソースの中でも特に)次の節を参照してください。
AEM 用 GraphQL の実装は、標準の GraphQL Java™ ライブラリをベースにしています。以下を参照してください。
GraphQL 用語 graphql-terminology
GraphQL では次を使用します。
-
- スキーマは、コンテンツフラグメントモデルに基づいて AEM で生成されます。
- GraphQL では、スキーマを使用して、AEM 用 GraphQL の実装で使用可能なタイプと操作を提供します。
-
-
GraphQL クエリに応答し、GraphQL スキーマへのアクセスを提供する AEM 内のパス。
-
詳しくは、GraphQL エンドポイントの有効化を参照してください。
-
ベストプラクティスを含む包括的な詳細については、「(GraphQL.org) GraphQL の概要」を参照してください。
GraphQL クエリタイプ graphql-query-types
GraphQL では、次のいずれかを返すクエリを実行できます。
-
1 つのエントリ
AEM は、クエリ(両方のタイプ)を Dispatcher と CDN によってキャッシュできる永続クエリに変換する機能を提供します。
GraphQL クエリのベストプラクティス(Dispatcher と CDN) graphql-query-best-practices
永続クエリは、パブリッシュインスタンスで次のように使用することをお勧めします。
- キャッシュされます
- AEM で一元管理されます
POST リクエストを使用する GraphQL クエリは、キャッシュされないのでお勧めしません。そのため、デフォルトのインスタンスでは、Dispatcher はそれらのクエリをブロックするように設定されています。
GraphQL は GET リクエストもサポートしていますが、これらのリクエストは制限(URL の長さなど)に達する可能性があり、これは永続クエリを使用することで回避できます。
詳しくは、永続クエリのキャッシュの有効化を参照してください。
GraphiQL インターフェイス graphiql-interface
標準の GraphiQL インターフェイスの実装は、AEM GraphQL で使用できます。
このインターフェイスを使用すると、クエリを直接入力してテストできます。
例:
http://localhost:4502/content/graphiql.html
構文のハイライト表示、オートコンプリート、自動候補表示などの機能と共に、履歴およびオンラインドキュメントが用意されています。
オーサー環境とパブリッシュ環境の使用例 use-cases-author-publish-environments
使用例は、AEM 環境のタイプによって異なる場合があります。
-
パブリッシュ環境の使用目的:
- JS アプリケーションのデータのクエリ(標準の使用例)
-
オーサー環境の使用目的:
-
「コンテンツ管理用」のデータのクエリ:
- AEM の GraphQL は読み取り専用の API です。
- REST API は、CR(U)D の操作に使用できます。
-
権限 permission
Assets にアクセスするには権限が必要です。
GraphQL クエリは、基になるリクエストの AEM ユーザーの権限で実行されます。ユーザーが一部の(Assets として保存された)フラグメントへの読み取りアクセス権を持っていない場合、ユーザーは結果セットの一部になりません。
また、ユーザーが GraphQL クエリを実行するには、GraphQL エンドポイントへのアクセス権を持っている必要があります。
スキーマ生成 schema-generation
GraphQL は、型指定された API です。つまり、データは型別に明確に構造化され編成される必要があります。
GraphQL の仕様には、特定のインスタンス上のデータをクエリするための堅牢な API を作成する方法に関する一連のガイドラインが用意されています。これらのガイドラインを完了するには、クライアントは、クエリに必要なすべての型を含むスキーマを取得する必要があります。
コンテンツフラグメントの場合、GraphQL スキーマ(構造とタイプ)は、有効 なコンテンツフラグメントモデルとそれらのデータタイプに基づいています。
例えば、ユーザーが Article
というコンテンツフラグメントモデルを作成した場合、AEM は GraphQL タイプ ArticleModel
を生成します。このタイプに含まれるフィールドは、モデルで定義されているフィールドとデータタイプに対応しています。さらに、articleByPath
や articleList
など、このタイプで動作するクエリのいくつかのエントリポイントを作成します。
-
コンテンツフラグメントモデル:
-
対応する GraphQL スキーマ(GraphiQL 自動生成ドキュメントからの出力):
この画像では、生成された型
ArticleModel
に複数のフィールドが含まれていることがわかります。-
そのうちの 3 つ(
author
、main
、referencearticle
)は、ユーザーが管理しています。 -
その他のフィールドは AEM によって自動的に追加されたもので、特定のコンテンツフラグメントに関する情報を提供する便利な手段となっています。この例では、
(ヘルパーフィールド)_path
、_metadata
、_variations
。
-
-
ユーザーが Article モデルに基づいてコンテンツフラグメントを作成すると、GraphQL を使用してそれをクエリできます。例については、(GraphQL で使用するコンテンツフラグメント構造のサンプルに基づいた)サンプルクエリを参照してください。
AEM 用 GraphQL では、スキーマには柔軟性があります。この柔軟性は、コンテンツフラグメントモデルを作成、更新、削除するたびに、スキーマが自動生成されることを意味します。また、コンテンツフラグメントモデルを更新すると、データスキーマキャッシュも更新されます。
Sites GraphQL サービスは、コンテンツフラグメントモデルに対する変更を(バックグラウンドで)リッスンします。更新が検出されると、スキーマのその部分だけが再生成されます。この最適化により、時間が節約され、安定性も確保されます。
例えば、次のようになります。
-
Content-Fragment-Model-1
とContent-Fragment-Model-2
を含んだパッケージをインストールすると、Model-1
およびModel-2
の GraphQL タイプが生成されます。
-
次に
Content-Fragment-Model-2
を変更すると、-
Model-2
GraphQL のタイプのみが更新されます。 -
一方で
Model-1
は変わりません。
-
スキーマは、GraphQL クエリと同じエンドポイントを通じて提供され、クライアントはスキーマが拡張子 GQLschema
で呼び出されることに対処します。例えば、/content/cq:graphql/global/endpoint.GQLschema
で単純な GET
リクエストを実行すると、text/x-graphql-schema;charset=iso-8859-1
の Content-type を持つスキーマが出力されます。
スキーマの生成 - 未公開のモデル schema-generation-unpublished-models
コンテンツフラグメントがネストされると、親のコンテンツフラグメントモデルは公開されますが、参照モデルは公開されません。
この場合、AEM は親コンテンツフラグメントモデルの 不完全な スキーマを生成します。非公開のモデルに依存するフラグメント参照がスキーマから削除されることを意味します。
フィールド fields
スキーマ内には、次の 2 つの基本的なカテゴリに属する個々のフィールドがあります。
-
ユーザーが生成するフィールド
選択されたフィールドタイプを使用して、コンテンツフラグメントモデルの設定方法に基づいてフィールドが作成されます。フィールド名は、データタイプ の「プロパティ名」フィールドから取得されます。
- ユーザーが特定のデータタイプを設定できるので、レンダリング形式 設定も考慮する必要があります。例えば、1 行のテキストフィールドに複数の 1 行のテキストを含めるように設定するには、ドロップダウンから「
multifield
」を選択します。
- ユーザーが特定のデータタイプを設定できるので、レンダリング形式 設定も考慮する必要があります。例えば、1 行のテキストフィールドに複数の 1 行のテキストを含めるように設定するには、ドロップダウンから「
-
AEM の GraphQL も、複数のヘルパーフィールドを生成します。
これらは、コンテンツフラグメントを識別するためや、コンテンツフラグメントに関する詳細を取得するために使用されます。
データタイプ data-types
AEM 用 GraphQL では一連のタイプをサポートしています。サポートされているすべてのコンテンツフラグメントモデルデータ型と、それに対応する GraphQL 型を以下の表に示します。
String
、[String]
String
Float
、[Float]
Boolean
Calendar
onlyDate
、onlyTime
、dateTime
の 3 つです。String
[String]
String
単一のフィールド:
Model
- 直接参照されるモデル型マルチフィールド(1 つの参照タイプ):
[Model]
- 型の配列 Model
(配列から直接参照)複数の参照型を持つマルチフィールド:
[AllFragmentModels]
- 和集合型を持つ配列から参照される、すべてのモデル型の配列ヘルパーフィールド helper-fields
ユーザー生成フィールドのデータ型に加えて、AEM 用 GraphQL では、コンテンツフラグメントの識別やコンテンツフラグメントに関する追加情報の提供に役立つ多数の ヘルパー フィールドも生成されます。
これらのヘルパーフィールドは、ユーザーが定義したものと自動生成されたものを区別するために、先頭に _
が付きます。
パス path
パスフィールドは、AEM GraphQL で識別子として使用され、AEM リポジトリ内のコンテンツフラグメントアセットのパスを表します。このパスは、次の理由で、コンテンツフラグメントの識別子として選択されます。
- AEM 内で一意である
- 取得しやすい
次のコードでは、コンテンツフラグメントモデル Person
に基づいて作成されたすべてのコンテンツフラグメントのパスを表示します。
{
personList {
items {
_path
}
}
}
特定のタイプのコンテンツフラグメントを 1 つ取得するには、まずそのパスも決定する必要があります。例:
{
authorByPath(_path: "/content/dam/path/to/fragment/john-doe") {
item {
_path
firstName
name
}
}
}
サンプルクエリ - ある 1 つの特定の都市フラグメントを参照してください。
メタデータ metadata
また、AEM では GraphQL を通じて、コンテンツフラグメントのメタデータも公開します。メタデータは、次のようなコンテンツフラグメントを記述する情報です。
- コンテンツフラグメントのタイトル
- サムネールのパス
- コンテンツフラグメントの説明
- および作成された日付など。
メタデータはスキーマエディターで生成され、特定の構造を持たないので、コンテンツフラグメントのメタデータを公開するために GraphQL 型 TypedMetaData
が実装されました。TypedMetaData
では、次のスカラー型でグループ化された情報を公開します。
stringMetadata:[StringMetadata]!
stringArrayMetadata:[StringArrayMetadata]!
intMetadata:[IntMetadata]!
intArrayMetadata:[IntArrayMetadata]!
floatMetadata:[FloatMetadata]!
floatArrayMetadata:[FloatArrayMetadata]!
booleanMetadata:[BooleanMetadata]!
booleanArrayMetadata:[booleanArrayMetadata]!
calendarMetadata:[CalendarMetadata]!
calendarArrayMetadata:[CalendarArrayMetadata]!
各スカラー型は、名前と値の 1 つのペアを表すか、名前と値のペアの配列を表します。このペアの値は、グループ化されたときの型になります。
例えば、コンテンツフラグメントのタイトルを取得する場合は、このプロパティが String 型プロパティであるためで、すべての String 型メタデータをクエリすることになります。
メタデータをクエリするには、次のようにします。
{
personByPath(_path: "/content/dam/path/to/fragment/john-doe") {
item {
_path
_metadata {
stringMetadata {
name
value
}
}
}
}
}
生成された GraphQL スキーマを表示するには、すべてのメタデータ GraphQL 型を表示します。すべてのモデルタイプは同じ TypedMetaData
を持ちます。
StringMetadata
と StringArrayMetadata
はどちらも、リポジトリに格納されているものについての指定であり、その取得手段についての指定ではありません。stringMetadata
フィールドを呼び出すことで、String
としてリポジトリに保存されているすべてのメタデータの配列を受け取ります。また、stringArrayMetadata
を呼び出した場合、String[]
としてリポジトリに格納されているすべてのメタデータの配列を受け取ります。詳しくは、メタデータのサンプルクエリ - 「GB」という賞のメタデータのリストを参照してください。
バリエーション variations
コンテンツフラグメントのバリエーションに対するクエリを簡略化するために、_variations
フィールドが実装されています。次に例を示します。
{
personByPath(_path: "/content/dam/path/to/fragment/john-doe") {
item {
_variations
}
}
}
_variations
」フィールドには master
バリエーションが含まれません。詳しくは、サンプルクエリ - 名前付きバリエーションを持つすべての都市を参照してください。
GraphQL 変数 graphql-variables
GraphQL では、クエリに変数を含めることができます。詳細情報は、変数に関する GraphQL のドキュメントを参照してください。
例えば、特定のバリエーションを持つ Article
タイプのコンテンツフラグメントをすべて取得するには、次のように、GraphiQL で変数 variation
を指定します。
### query
query GetArticlesByVariation($variation: String!) {
articleList(variation: $variation) {
items {
_path
author
_variations
}
}
}
### in query variables
{
"variation": "uk"
}
GraphQL ディレクティブ graphql-directives
GraphQL では、GraphQL ディレクティブと呼ばれる変数に基づいてクエリを変更する可能性があります。
例えば、変数 includePrice
に基づいて、すべての AdventureModels
のクエリに adventurePrice
フィールドを含めることができます。
### query
query GetAdventureByType($includePrice: Boolean!) {
adventureList {
items {
adventureTitle
adventurePrice @include(if: $includePrice)
}
}
}
### in query variables
{
"includePrice": true
}
フィルタリング filtering
GraphQL クエリでフィルタリングを使用して、特定のデータを返すこともできます。
フィルタリングでは、論理演算子と論理式に基づいた構文を使用します。
最もアトミックな部分は、特定のフィールドの内容に適用できる単一の式です。フィールドの内容を指定された定数値と比較します。
例えば、次の式はフィールドの内容と値 some text
を比較し、内容と値が等しい場合は成功します。それ以外の場合、式は失敗します。
{
value: "some text"
_op: EQUALS
}
次の演算子を使用して、フィールドを特定の値と比較できます。
EQUALS
String
、ID
、Boolean
EQUALS_NOT
String
、ID
CONTAINS
String
{ value: "mas", _op: CONTAINS }
が Christmas
、Xmas
、master
などと一致)CONTAINS_NOT
String
STARTS_WITH
ID
{ value: "/content/dam/", _op: STARTS_WITH
は /content/dam/path/to/fragment
と一致するが、/namespace/content/dam/something
とは一致しない)EQUAL
Int
、Float
UNEQUAL
Int
、Float
GREATER
Int
、Float
GREATER_EQUAL
Int
、Float
LOWER
Int
、Float
LOWER_EQUAL
Int
、Float
AT
Calendar
、Date
、Time
NOT_AT
Calendar
、Date
、Time
BEFORE
Calendar
、Date
、Time
AT_OR_BEFORE
Calendar
、Date
、Time
AFTER
Calendar
、Date
、Time
AT_OR_AFTER
Calendar
、Date
、Time
また、次のように式の評価方法を変更する追加のオプションを指定できるタイプもあります。
_ignoreCase
String
time
の値は TIME
、time
、tImE
…に一致)_sensitiveness
Float
float
値が同じと見なされるための一定のマージンを許可します(float
値の内部表現による技術的な制限を回避するため)。このオプションはパフォーマンスに悪影響を及ぼす可能性があるので、避ける必要があります。式は、論理演算子(_logOp
)を使用して設定に組み合わせることができます。
OR
- 少なくとも 1 つの式が成功した場合、式のセットは成功しますAND
- すべての式が成功した場合、式のセットは成功します(デフォルト)
各フィールドは、独自の式セットでフィルタリングできます。フィルター引数で指定されたすべてのフィールドの式セットは、最終的に独自の論理演算子で結合されます。
フィルター定義(filter
引数としてクエリに渡される)には次が含まれます。
- 各フィールドのサブ定義(フィールド名を使用してアクセスできます。例えば、データ(フィールド)タイプの
lastName
フィールドのフィルターにはlastName
フィールドがあります) - 各サブ定義には、式セットを提供する
_expressions
配列と、式を組み合わせる必要がある論理演算子を定義する_logOp
フィールドが含まれます - 各式は、値(
value
フィールド)と演算子(_operator
フィールド)によって定義され、フィールドの内容を比較する必要があります
項目を AND
と組み合わせる場合は _logOp
を、等しいかどうかを確認する場合は _operator
を省略できます(これらの値はデフォルトのため)。
次の例は、大文字と小文字を区別せずに、Provo
が lastName
である、または sjö
を含むすべてのユーザーをフィルタリングする完全なクエリを示しています。
{
authorList(filter: {
lastname: {
_logOp: OR
_expressions: [
{
value: "sjö",
_operator: CONTAINS,
_ignoreCase: true
},
{
value: "Provo"
}
]
}
}) {
items {
lastName
firstName
}
}
}
オプション変数を使用して GraphQL クエリを実行する際、オプション変数に特定の値が指定されて いない 場合、その変数はフィルター評価で無視されます。つまり、クエリ結果には、フィルター変数に関連するプロパティのすべての値(null
と null
以外の両方)が含まれます。
null
値が 明示的に 指定されている場合、フィルターは、対応するプロパティの null
値のみを照合します。例えば、以下のクエリでは、lastName
プロパティの値が指定されていません。
query getAuthorsFilteredByLastName($authorLastName: String) {
authorList(filter:
{
lastName: {_expressions: {value: $authorLastName}
}}) {
items {
lastName
}
}
}
次のように、すべての作成者が返されます。
{
"data": {
"authorList": {
"items": [
{
"lastName": "Hammer"
},
{
"lastName": "Provo"
},
{
"lastName": "Wester"
},
{
"lastName": null
},
...
]
}
}
}
ネストされたフィールドに対してフィルターを適用することもできますが、パフォーマンスの問題が発生する可能性があるため、お勧めしません。
その他の例については、以下を参照してください。
-
- さらに、サンプルクエリ用に準備されているサンプルコンテンツおよび構造
並べ替え sorting
この機能を使用すると、指定したフィールドに従ってクエリ結果を並べ替えることができます。
並び替え条件:
-
フィールドパスを表すコンマ区切りの値のリスト
-
リスト内の最初のフィールドで、主な並べ替え順を定義します
- 2 番目のフィールドは、主な並べ替え条件の 2 つの値が等しい場合に使用されます
- 最初の 2 つの条件が等しい場合は 3 番目のフィールドを、などのように使用されます
-
field1.subfield.subfield
などのドット表記になります。
-
-
(オプション)並べ替えの方向
- ASC(昇順)または DESC(降順)。デフォルトでは ASC が適用されます
- 方向は、フィールドごとに指定できます。つまり、あるフィールドを昇順で、別のフィールドを降順で並べ替えることができます(name、firstName DESC)
例:
query {
authorList(sort: "lastName, firstName") {
items {
firstName
lastName
}
}
}
次のようにすることもできます。
{
authorList(sort: "lastName DESC, firstName DESC") {
items {
lastName
firstName
}
}
}
また、nestedFragmentname.fieldname
の形式を使用して、ネストされたフラグメント内のフィールドで並べ替えることもできます。
例:
query {
articleList(sort: "authorFragment.lastName") {
items {
title
authorFragment {
firstName
lastName
birthDay
}
slug
}
}
}
ページング paging
この機能を使用すると、リストを返すクエリタイプに対してページングを実行できます。 次の 2 つの方法があります。
List
クエリのoffset
とlimit
Paginated
クエリのfirst
とafter
リストクエリ - オフセットと制限 list-offset-limit
...List
クエリでは、offset
と limit
を使用して、特定の結果サブセットを返すことができます。
offset
:返される最初のデータセットを指定しますlimit
:返されるデータセットの最大数を指定します
例えば、完全な 結果リストの 5 番目の記事から開始して、最大 5 つの記事を含む結果のページを出力するには、次のようにします。
query {
articleList(offset: 5, limit: 5) {
items {
authorFragment {
lastName
firstName
}
}
}
}
-
ページングには安定した並べ替え順序が必要です。同じ結果セットの異なるページをリクエストする複数のクエリで正しく動作するようにします。デフォルトでは、結果セットの各項目のリポジトリパスを使用して、順序が常に同じであることを確認します。異なる並べ替え順を使用していて、その並べ替えを JCR クエリレベルで実行できない場合、パフォーマンスに悪影響を及ぼします。これは、ページが決定される前に結果セット全体をメモリに読み込む必要があるからです。
-
オフセットが大きいほど、JCR クエリの結果セット全体から項目をスキップするのに時間がかかります。大規模な結果セットに対する代替ソリューションは、
first
およびafter
メソッドでページ分割されたクエリを使用することです。
ページ分割されたクエリ - first と after paginated-first-after
...Paginated
クエリタイプは、ほとんどの ...List
クエリタイプの機能(フィルタリング、並べ替え)を再利用しますが、offset
/limit
引数の代わりに、GraphQL カーソル接続仕様で定義されている first
/after
引数を使用します。GraphQL の概要では、堅苦しくない概要を見つけることができます。
first
:返される最初のn
個の項目。
デフォルトは、50
です。
最大値は100
です。after
:リクエストされたページの先頭を決定するカーソル。カーソルで表される項目は結果セットに含まれません。項目のカーソルは、edges
構造体のcursor
フィールドによって決定されます。
例えば、完全な 結果リスト内の指定されたカーソル項目から開始して、最大 5 つのアドベンチャーを含む結果のページを出力します。
query {
adventurePaginated(first: 5, after: "ODg1MmMyMmEtZTAzMy00MTNjLThiMzMtZGQyMzY5ZTNjN2M1") {
edges {
cursor
node {
title
}
}
pageInfo {
endCursor
hasNextPage
}
}
}
-
デフォルトのページングでは、結果の順序が常に同じになるように、フラグメントを表すリポジトリノードの UUID を順序付けに使用します。
sort
を使用すると、UUID は一意の並べ替えを保証するために暗黙的に使用されます。同じ並べ替えキーを持つ 2 つの項目の場合も同様です。 -
内部の技術的制約により、ネストされたフィールドに並べ替えとフィルタリングを適用すると、パフォーマンスが低下します。そのため、ルートレベルで格納されたフィルターや並べ替えのフィールドを使用してください。これは、ページ分割された大きな結果セットをクエリする場合にも推奨される方法です。
GraphQL の永続クエリ - Dispatcher でのキャッシュの有効化 graphql-persisted-queries-enabling-caching-dispatcher
永続化されたクエリのキャッシュは、Dispatcher ではデフォルトで有効になっていません。複数のオリジンで CORS(クロスオリジンリソース共有)を使用している場合、Dispatcher 設定を確認し、場合によっては更新する必要があるので、デフォルトで有効にすることはできません。
Vary
ヘッダーはキャッシュされません。永続クエリのキャッシュの有効化 enable-caching-persisted-queries
永続クエリのキャッシュを有効にするには、Dispatcher 設定ファイルを次のように更新する必要があります。
-
<conf.d/rewrites/base_rewrite.rules>
code language-xml # Allow the dispatcher to be able to cache persisted queries - they need an extension for the cache file RewriteCond %{REQUEST_URI} ^/graphql/execute.json RewriteRule ^/(.*)$ /$1;.json [PT]
note note NOTE Dispatcher がすべての永続クエリ URL にサフィックス .json
を追加して、結果をキャッシュできるようにします。これは、キャッシュ可能なドキュメントに対する Dispatcher の要件にクエリが確実に従うようにするためです。詳しくは、Dispatcher がドキュメントを返す方法を参照してください。 -
<conf.dispatcher.d/filters/ams_publish_filters.any>
code language-xml # Allow GraphQL Persisted Queries & preflight requests /0110 { /type "allow" /method '(GET|POST|OPTIONS)' /url "/graphql/execute.json*" }
Dispatcher での CORS の設定 cors-configuration-in-dispatcher
CORS リクエストを使用するお客様は、Dispatcher で CORS の設定を確認および更新する必要が生じる場合があります。
-
Origin
ヘッダーは、Dispatcher を介して AEM パブリッシュに渡さないでください。clientheaders.any
ファイルを確認します。
-
代わりに、許可されたオリジンに対して、Dispatcher レベルで CORS リクエストを評価する必要があります。また、この方法では、CORS 関連のヘッダーが、どの場合でも 1 か所で正しく設定されます。
- このような設定は
vhost
ファイルに追加されます。次に設定例を示します。簡単にするために、CORS 関連の部分のみが提供されています。特定のユースケースに合わせて調整してください。
code language-xml <VirtualHost *:80> ServerName "publish" # ... <IfModule mod_headers.c> Header add X-Vhost "publish" ################## Start of the CORS specific configuration ################## SetEnvIfExpr "req_novary('Origin') == ''" CORSType=none CORSProcessing=false SetEnvIfExpr "req_novary('Origin') != ''" CORSType=cors CORSProcessing=true CORSTrusted=false SetEnvIfExpr "req_novary('Access-Control-Request-Method') == '' && %{REQUEST_METHOD} == 'OPTIONS' && req_novary('Origin') != '' " CORSType=invalidpreflight CORSProcessing=false SetEnvIfExpr "req_novary('Access-Control-Request-Method') != '' && %{REQUEST_METHOD} == 'OPTIONS' && req_novary('Origin') != '' " CORSType=preflight CORSProcessing=true CORSTrusted=false SetEnvIfExpr "req_novary('Origin') -strcmatch 'https://%{HTTP_HOST}*'" CORSType=samedomain CORSProcessing=false # For requests that require CORS processing, check if the Origin can be trusted SetEnvIfExpr "%{HTTP_HOST} =~ /(.*)/ " ParsedHost=$1 ################## Adapt the regex to match CORS origin for your environment SetEnvIfExpr "env('CORSProcessing') == 'true' && req_novary('Origin') =~ m#(https://.*.your-domain.tld(:\d+)?$)#" CORSTrusted=true # Extract the Origin header SetEnvIfNoCase ^Origin$ ^https://(.*)$ CORSTrustedOrigin=https://$1 # Flush If already set Header unset Access-Control-Allow-Origin Header unset Access-Control-Allow-Credentials # Trusted Header always set Access-Control-Allow-Credentials "true" "expr=reqenv('CORSTrusted') == 'true'" Header always set Access-Control-Allow-Origin "%{CORSTrustedOrigin}e" "expr=reqenv('CORSTrusted') == 'true'" Header always set Access-Control-Allow-Methods "GET" "expr=reqenv('CORSTrusted') == 'true'" Header always set Access-Control-Max-Age 1800 "expr=reqenv('CORSTrusted') == 'true'" Header always set Access-Control-Allow-Headers "Origin, Accept, X-Requested-With, Content-Type, Access-Control-Request-Method, Access-Control-Request-Headers" "expr=reqenv('CORSTrusted') == 'true'" # Non-CORS or Not Trusted Header unset Access-Control-Allow-Credentials "expr=reqenv('CORSProcessing') == 'false' || reqenv('CORSTrusted') == 'false'" Header unset Access-Control-Allow-Origin "expr=reqenv('CORSProcessing') == 'false' || reqenv('CORSTrusted') == 'false'" Header unset Access-Control-Allow-Methods "expr=reqenv('CORSProcessing') == 'false' || reqenv('CORSTrusted') == 'false'" Header unset Access-Control-Max-Age "expr=reqenv('CORSProcessing') == 'false' || reqenv('CORSTrusted') == 'false'" # Always vary on origin, even if its not there. Header merge Vary Origin # CORS - send 204 for CORS requests which are not trusted RewriteCond expr "reqenv('CORSProcessing') == 'true' && reqenv('CORSTrusted') == 'false'" RewriteRule "^(.*)" - [R=204,L] ################## End of the CORS specific configuration ################## </IfModule> <Directory /> # ... </Directory> # ... </VirtualHost>
- このような設定は
AEM 用の GraphQL - 拡張機能の概要 graphql-extensions
AEM 用の GraphQL でのクエリの基本操作は、標準の GraphQL 仕様に従います。AEM での GraphQL クエリには、次のような拡張機能があります。
-
結果が 1 つだけ必要な場合:
- 市区町村などのモデル名を使用します。
-
結果のリストを想定している場合:
- モデル名に
List
を付け加えます(例:cityList
) - サンプルクエリ - すべての都市に関するすべての情報を参照してください
これにより、以下のことが可能になります。
-
ASC
: 昇順DESC
: 降順
-
次のいずれかを使用して、結果のページを返します。
-
サンプルクエリ - すべての都市に関するすべての情報を参照してください
- モデル名に
-
フィルター
includeVariations
はList
のクエリタイプに含まれます。クエリ結果でコンテンツフラグメントのバリエーションを取得するには、includeVariations
フィルターをtrue
に設定する必要があります。note caution CAUTION フィルター includeVariations
は、システム生成フィールド_variation
と併用できません。 -
論理和(OR)を使用する場合:
_logOp: OR
を使用します- サンプルクエリ - 「Jobs」または「Smith」という名前を持つすべての人物を参照してください
-
論理積(AND)も存在しますが、(多くの場合)暗黙的です
-
コンテンツフラグメントモデル内のフィールドに対応するフィールド名に対してクエリを実行できます
- サンプルクエリ - ある会社の CEO と従業員の詳細を参照してください
-
モデルのフィールドに加えて、次のようなシステム生成フィールドがあります(フィールド名の先頭にアンダースコアが付きます)。
-
コンテンツの場合:
-
_locale
:言語を表示します(言語マネージャーに基づく)- 特定ロケールの複数のコンテンツフラグメントのサンプルクエリを参照してください
-
_metadata
:フラグメントのメタデータを表示します- メタデータのサンプルクエリ - 「GB」という賞のメタデータのリストを参照してください
-
_model
:コンテンツフラグメントモデル(パスとタイトル)のクエリを許可します- モデルからのコンテンツフラグメントモデルのサンプルクエリを参照してください
-
_path
:リポジトリ内のコンテンツフラグメントへのパス- サンプルクエリ - 1 つの特定の都市フラグメントを参照してください
-
_reference
:参照(リッチテキストエディターでのインライン参照など)を表示します -
_variation
:コンテンツフラグメント内の特定のバリエーションを表示しますnote note NOTE コンテンツフラグメントに指定されたバリエーションが存在しない場合は、プライマリバリエーションが(フォールバック)デフォルトとして返されます。 note caution CAUTION システム生成フィールド _variation
は、フィルターincludeVariations
と併用できません。- サンプルクエリ - 名前付きバリエーションを持つすべての都市を参照してください
-
_tags
:タグを含むコンテンツフラグメントまたはバリエーションの ID を表示します。このリストはcq:tags
識別子の配列です。- サンプルクエリ - 市区町村の区切り文字としてタグ付けされた、すべての都市の名前を参照してください。
- 詳しくは、特定のタグが添付された、任意のモデルのコンテンツフラグメントバリエーションのサンプルクエリを参照してください。
note note NOTE また、コンテンツフラグメントのメタデータを一覧表示して、タグをクエリできます。
-
-
操作の場合:
-
_operator
:特定の演算子(EQUALS
、EQUALS_NOT
、GREATER_EQUAL
、LOWER
、CONTAINS
、STARTS_WITH
)を適用します -
_apply
:特定の条件(例:AT_LEAST_ONCE
)を適用します -
_ignoreCase
:クエリの実行時に大文字と小文字を区別しません
-
-
-
GraphQL のユニオン型がサポートされています
... on
を使用します
-
ネストされたフラグメントに対するクエリ時のフォールバック:
- 要求されたバリエーションがネストされたフラグメントに存在しない場合、プライマリ バリエーションが返されます。
CORS フィルター cors-filter
GraphQL エンドポイントにアクセスするには、顧客の Git リポジトリに CORS ポリシーを設定します。この設定は、1 つ以上の目的のエンドポイントに対して適切な OSGi CORS 設定ファイルを追加することで実行されます。
この設定では、アクセスを許可する必要がある、信頼できる web サイトオリジン alloworigin
または alloworiginregexp
を指定する必要があります。
例えば、https://my.domain
の GraphQL エンドポイントと永続クエリのエンドポイントへのアクセスを許可するには、以下を使用します。
{
"supportscredentials":true,
"supportedmethods":[
"GET",
"HEAD",
"POST"
],
"exposedheaders":[
""
],
"alloworigin":[
"https://my.domain"
],
"maxage:Integer":1800,
"alloworiginregexp":[
""
],
"supportedheaders":[
"Origin",
"Accept",
"X-Requested-With",
"Content-Type",
"Access-Control-Request-Method",
"Access-Control-Request-Headers"
],
"allowedpaths":[
"/content/_cq_graphql/global/endpoint.json",
"/graphql/execute.json/.*"
]
}
エンドポイントのバニティーパスを設定した場合は、allowedpaths
でも使用できます。
リファラーフィルター referrer-filter
CORS 設定に加えて、サードパーティホストからのアクセスを許可するために、リファラーフィルターを設定する必要があります。
このフィルターは、以下を行う適切な OSGi リファラーフィルター設定ファイルを追加することで実行されます。
- 信頼できる web サイトのホスト名(
allow.hosts
またはallow.hosts.regexp
)を指定する。 - この名前のホストに対するアクセスを許可する。
例えば、リファラー my.domain
を持つリクエストにアクセスを許可するには、次の操作を行います。
{
"allow.empty":false,
"allow.hosts":[
"my.domain"
],
"allow.hosts.regexp":[
""
],
"filter.methods":[
"POST",
"PUT",
"DELETE",
"COPY",
"MOVE"
],
"exclude.agents.regexp":[
""
]
}
- 信頼できるドメインにのみアクセスを許可する
- 機密情報が公開されていないことを確認する
- ワイルドカードの [*] 構文を使用しない。この機能を使用すると、GraphQL エンドポイントへの認証済みアクセスが無効になり、エンドポイントが世界中に公開されることになります。
制限事項 limitations
潜在的な問題から保護するために、クエリにはデフォルトの制限が課されています。
- クエリには 100 万(1024 * 1024)文字を超える文字を含めることはできません
- クエリには、15,000 個を超えるトークンを含めることはできません
- クエリには、200,000 個を超える空白トークンを含めることはできません
また、次の事項にも注意する必要があります。
-
GraphQL クエリに 2 つ(またはそれ以上)のモデルで同じ名前のフィールドが含まれており、次の条件が満たされる場合、フィールド競合エラーが返されます。
-
したがって
- 2 つ(またはそれ以上のモデル)が可能な参照として使用されます(コンテンツフラグメント参照で許可された モデルタイプ として定義されている場合)。
また
- これら 2 つのモデルには共通の名前を持つフィールドがあります。つまり、両方のモデルに同じ名前が存在します。
また
- これらのフィールドは異なるデータタイプです。
-
次に例を示します。
-
異なるモデルを持つ 2 つ(またはそれ以上)のフラグメント(
M1
、M2
など)が、別のフラグメントからの参照(コンテンツ参照またはフラグメント参照)として使用される場合。例:Fragment1
MultiField/List
-
異なるモデルを持つこれら 2 つのフラグメント(
M1
、M2
)には、同じ名前のフィールドがありますが、タイプが異なります。
次に例を示します。M1.Title
はText
M2.Title
はText/MultiField
-
GraphQL クエリに
Title
フィールドが含まれる場合、フィールド競合エラーが発生します。
-
-
認証 authentication
コンテンツフラグメントに対するリモート AEM GraphQL クエリの認証を参照してください。
FAQ faqs
次のような質問が寄せられました。
-
Q:「AEM 用 GraphQL API と Query Builder API の違いは何ですか?」
- A:「AEM GraphQL API は JSON 出力の完全な制御が可能であり、コンテンツをクエリするための業界標準になっています。今後、AEM は AEM GraphQL API への投資を計画しています。」
チュートリアル - AEM ヘッドレスと GraphQL をはじめる前に tutorial
実践的なチュートリアルを探している場合は、AEM ヘッドレスおよび GraphQL 入門をご覧ください。これは、AEM の GraphQL API を使用してコンテンツを構築および公開し、ヘッドレス CMS シナリオで外部アプリによって使用する方法を説明する包括的なチュートリアルです。