1724533759
2024-08-24 12:44:54
空を見上げてください。鳥です。いや、待ってください。Optimizely Graph です。これはブログ投稿シリーズの第 2 部で、Optimizely Graph を使用して .NET Core で完全に機能するヘッドレス サイトを構築する方法を探ります。この投稿では、Optimizely Graph が強力な検索およびクエリ エンジン (古き良き Episerver Find と同等) であるだけでなく、コンテンツ配信 API を完全に置き換えることができることも説明します。
このシリーズを初めて読む方は、最初の投稿を読んでください。 ここ。
最初の投稿は、古き良き Alloy から Optimizely SaaS CMS にコンテンツをインポートし、組み込みのグラフ インデックスにもインポートするという、少しソフトな内容から始まりました。最後に、組み込みツールを使用してグラフを調べる方法を示す短いビデオを掲載しました。
しかし、GraphQL を扱ったことがある人なら、それだけではないことが分かるでしょう。ここでは、そうしたオプションのいくつかを取り上げ、ヘッドレス サイトに必要なコンテンツを取得するためにクエリを実行する方法を説明します。この記事では、このシリーズの目標である、Graph を使用してヘッドレス .NET Core サイトで何らかのバージョンの Alloy を実行するために必要なことだけに焦点を当てます。Optimizely Content Graph には多数の機能があり、ここではそのうちのいくつかについてのみ触れますが、公式ドキュメントをここで確認することを強くお勧めします。 https://docs.developers.optimizely.com/platform-optimizely/v1.4.0-optimizely-graph/docs/introduction-optimizely-graph
ContentGraphには現在2つの「フレーバー」があります
ContentGraph の詳細とクエリ方法について詳しく説明する前に、Optimizely CMS ContentGraph のスキーマには現在 2 つの異なるバージョンが存在することに注目する価値があります。
- もしあなたが 無料トライアルとしてグラフインデックスをリクエストする (または DXP 経由で入手)、CMS 12 に統合をインストールすると、インデックスを調べると、コンテンツが現在使用しているモデルとよく似ていることに気付くでしょう。IContent タイプがあり、すべてのフィールドは多かれ少なかれ予想どおりの場所にあり、名前も似ています。
- しかし、代わりに新しい SaaS CMS (このデモで使用しています) を起動すると、コンテンツ モデルは旧式の CMS から少し離れています。これは、コンテンツ管理のより一般的な理解に合わせて準備されているためです。これは、フィールドの命名とモデルの構造の両方に表れています。心配しないでください。基本的には同じものが得られますが、見つけるのに 2 回探す必要があるかもしれません。
たとえば、コンテンツ アイテムのデフォルト フィールド (名前、URL、キー、ステータスなど) の多くは、ルート内ではなく、「_metadata」ノードの下にあります。
クエリの実験
これで、ContentGraph を試し始める準備がほぼ整いました。SaaS CMS を使用している場合、または通常の CMS 12 への統合をインストールしている場合は、UI で GraphiQL プレイグラウンドにアクセスできます。
それ以外の場合は、「https://cg.optimizely.com/app/graphiql?auth=」を参照することもできます。[your single key]「」。
基本的に、インデックスの認証には 2 つの方法があります。インデックスを取得すると、AppKey、シークレット、および単一のキーが取得されます。
単一キーを使用すると、グラフ内の公開されている (誰でも読み取り可能で公開されている) すべてのコンテンツに対して読み取り専用クエリを実行できます。
インデックスに書き込む場合、または制限されたコンテンツにアクセスする場合は、認証ヘッダー (base64 エンコード、基本認証スタイル) でキーとシークレットを使用する必要があります。通常、これは、外部からカスタム コンテンツを最適化してインデックス化する場合 (非常に楽しい)、Webhook をサブスクライブする場合、またはインデックスにリンク マッピングなどを設定する場合に使用されます。
未公開のコンテンツのプレビューは、特別なプレビュー トークンを使用して行うこともできますが、これについては後で詳しく説明します。話がそれましたが、ここで重要なのは、開始するには、1 つのキーを取得して GraphiQL インターフェイスに移動することです。これは、実験して学習するのに最適な場所です。
最小限の結果
Find (検索とナビゲーション) と通常の ContentDelivery API の両方の操作に慣れている方法との大きな違いは、どちらのアプローチでも、要求したドキュメントごとにデフォルトで「すべて」が取得されることです。ただし、Graph では、要求したものだけが返されます。また、「ワイルドカード」はありません。クエリでフィールドを具体的に要求しないと、取得されません。最初はこれが少し面倒に感じましたが、トラフィックを最小限に抑え、どのクエリを送信するかを本当に考慮する必要があるため、むしろ好きになり始めました。
query MyQuery {
_Content {
items {
_metadata {
displayName
url {
hierarchical
}
key
created
lastModified
locale
status
types
}
}
}
}
たとえば、このクエリを見てみましょう。ここでは、「_Content」タイプのすべてのアイテムに対して、メタデータ プロパティ DisplayName、階層 URL、キー、作成日、最終変更日などを返すように要求しています。必要なすべてのフィールドを指定する必要があります。
欠点は、コンテンツを必要とするすべてのシナリオとすべてのコンテンツ タイプに対して、非常に詳細なカスタム クエリを大量に記述しなければならない可能性があることです。これはメンテナンスの悪夢です。ただし、これを解決するにはいくつかのコツがあります…
断片 ここで理解すべき最も重要な概念の 1 つは、基本的に、特定のプロパティ/タイプに対して取得するフィールドの再利用可能な定義を定義できる場所であるためです。これらは、クエリを構築するために使用する構成要素と考えてください。これらは必要な数だけ使用できます。
たとえば、私の Alloy サイトでは、StandardPage (またはそこから継承されたページ) であるすべてのページに MainBody フィールドと TeaserText フィールドがあることがわかっています。ここで、_Content タイプをクエリし、それが StandardPage に基づくタイプである場合は、必ずこれらのプロパティを含めるようにします。これを行うには、一般的なビルディング ブロックを作成します。この例では、これを「standardPageFragment」と呼び、クエリ ブロックの外側に含めます。その後、クエリ内で「…standardPageFragment」を呼び出すだけで参照できます。次のようになります。
query MyQuery {
_Content {
items {
_metadata {
displayName
url {
hierarchical
}
key
created
lastModified
locale
status
types
}
...standardPageFragment
}
}
}
fragment standardPageFragment on StandardPage{
MainBody{
html
}
TeaserText
}
注目すべき点は、すべてのタイプをフラグメントに定義できることです。たとえば、新しい SaaS スキーマの XhtmlString が、”html” フィールドを取得する必要があるオブジェクトになっていることに注目してください。もう 1 つのフィールドは “json” です。これは、独自の解析を行う場合に json 構造で取得することもできるためです。ここで、”richTextFragment” を定義して、必要なプロパティを常に正確に取得できるようにすることもできます。そして、フラグメント内でフラグメントを使用することもできます。
これは、ContentArea を扱うときに非常に便利です。基本的に、内部に他のフラグメントを含むフラグメントを定義でき、さらにそれ自体を再帰的に定義できるからです。また、ContentArea を使用すると、内部にコンテンツ領域を含むブロック (コンテンツ領域を含むブロックなど) を持つことももちろん可能です。たとえば、次のようになります。
query MyQuery {
_Content{
items{
...standardPageFragment
}
}
}
fragment standardPageFragment on StandardPage{
MainContentArea{
...iContentFragment
}
}
fragment iContentFragment on _IContent{
_metadata{
displayName
}
... on StandardPage{
MainContentArea{
...iContentFragment
}
}
}
再帰性は少々扱いにくい傾向がありますが、確かに動作させることは可能です。ただし、いくつかの注意点があり、 ドキュメント (私の経験では少し遅れているかもしれませんが)。
パラメータ化されたクエリ
クエリを作成するときは、当然ながらパラメータを渡す必要があります。たとえば、すべての製品ページの displayName をリストするクエリを実行するとします。
もちろん、ProductPage タイプ (_Content ではない) のみをクエリすることもできますが、ProductPage タイプには displayName を含む _metadata がありません。
そのため、この場合も引き続きすべての _Content をクエリしますが、次のようにフィルター パラメーターを追加して特定のタイプに制限します。
query MyQuery {
_Content(where: { _metadata: { types: { eq: "ProductPage" } } }) {
items {
_metadata {
displayName
}
}
}
}
ここで、Episerver Findの機能が実際に発揮されます。あらゆる種類の フィルタリング、 並べ替え パラメータとして機能し、 全文 そして セマンティック検索 多くの異なる言語で。これらの部分については今のところあまり深く掘り下げませんが、今後の投稿で取り上げるかもしれません。ファセットについても同様で、非常に強力ですが、この簡単な紹介の範囲外です。
しかし、基本的なフィルタリングに固執する場合、URL パスを指定して特定のページをフィルタリングできることが必要になります。また、フィルタリングする必要があるだけでなく、GraphQL クエリにさまざまなパスを渡すことも必要です。つまり、クエリ自体にパラメータとして追加する必要があります。次のようになります。

コンテンツ階層
もう 1 つ触れておく必要があるのは、ContentGraph からコンテンツ ツリーを取得する方法です。ナビゲーションで子ページへのリンクをリストするなどの操作を行う場合、これは非常に重要です。
幸いなことに、Linking を使用するとかなり簡単です。
ContentGraph の _Content にはデフォルトの親/子リンク設定があるため、ページの “_link” フィールドをクエリするだけで、子を取得できます。また、もちろん、特定の方法で並べ替えたり、一部の子だけを返したり、ページ区切りを使用したりしたい場合は、子をフィルター処理することもできます。
query MyQuery($path: String) {
_Page(where: { _metadata: { url: { hierarchical: { eq: $path } } } }) {
items {
_metadata {
displayName
url {
hierarchical
}
}
_link {
_Page {
items {
_metadata {
displayName
}
}
}
}
}
}
}
リンク機能は非常に強力な機能で、グラフ内のオブジェクト間のカスタム関係を設定し、リンク機能を使用してそれらを一緒にクエリすることもできます。もう一度、ぜひチェックしてみてください。 ドキュメント これについて。
内省
さて、この投稿が長くなりすぎる前に、シリーズの次の投稿に向けて「ウォーミングアップ」をさせてください。ここまで来ると、皆さんはちょっと圧倒されて、「これはコードが多そうだ」と思っているかもしれません。少なくとも、私がこれを紹介されたときはそう感じました。CMS のページに新しいプロパティを追加すると、クライアントの同様のモデル オブジェクトにもそれを追加する必要があると想像してみてください。おそらく、統合のマッピング ロジックや、グラフに送信される多数のクエリにも追加する必要があるでしょう。メンテナンスするのは悪夢のようですね。
さて、ここでやるべきことは、もちろん自動化することです。そしてもちろん、Optimizely の賢い人たちもそれについて考え、次のようなものを作りました。 https://github.com/episerver/graph-net-sdk これには、まさにそれを実行するのに役立つ CLI があります (少なくとも部分的には)。このツールは、クライアントの C# モデル クラスを生成しますが、それらを使用するために必要なクエリは生成しません。
そして、その努力には感謝しますが、生成されたモデル クラスはかなり静的で、私のすべてのニーズに望みどおりに適合しませんでした。そのため、最終的にはモデルとクエリを生成するための独自のツールをまとめることになりました。このシリーズの次の投稿でそれを共有する予定です。
それまでは、最後のクエリを 1 つ紹介しておきます。これは、ツールが使用するものと非常によく似ています。これは、ContentGraph に、スキーマ内にあるすべての型と、それらに含まれるフィールドを返すように要求するイントロスペクション クエリです。
query Introspection{
__schema {
queryType {
name
fields {
name
}
}
types {
name
fields {
name
type{
name
kind
ofType{
name
kind
}
}
}
}
}
}
#Optimizely #Graphのヘッドレスサイトコンテンツをクエリする興味深い方法を探る