背景と応用シナリオ
Salesforce 統合エンジニアとして、私は日々 Salesforce と外部システムを連携させるための最適なソリューションを模索しています。従来の連携シナリオでは、REST (Representational State Transfer) API が広く利用されてきました。しかし、特に複雑なユーザーインターフェースやモバイルアプリケーションとの連携において、REST API にはいくつかの課題が存在します。それは「オーバーフェッチング(Over-fetching)」と「アンダーフェッチング(Under-fetching)」という問題です。
オーバーフェッチングとは、API レスポンスにクライアントが必要としない余分なデータが含まれてしまうことです。例えば、取引先名と電話番号だけが必要なのに、REST API のエンドポイントが取引先の全項目を返してしまうケースがこれにあたります。一方、アンダーフェッチングは、必要なデータをすべて取得するために複数の API コールを行わなければならない状況を指します。例えば、「ある取引先の情報と、その取引先に関連するすべての取引先責任者の名前、そして各取引先責任者が担当する最新のケースを3件取得する」といった要件があった場合、REST API ではまず取引先を取得し、次に関連する取引先責任者を取得し、さらに各取引先責任者に対してループ処理でケースを取得する…といった具合に、複数のリクエストが必要になり、ネットワークの往復回数が増え、パフォーマンスの低下を招きます。
これらの課題を解決するために登場したのが GraphQL (グラフキューエル) です。GraphQL は Facebook (現 Meta) によって開発された API のためのクエリ言語であり、クライアントが必要なデータの構造をリクエストで正確に指定できるという大きな特徴を持っています。これにより、クライアントは一度のリクエストで、過不足なく、まさに必要なデータだけを取得できるようになります。
Salesforce プラットフォームでは、この GraphQL の能力を活用できる GraphQL API が提供されています。これは特に、以下のような応用シナリオで絶大な効果を発揮します。
主な応用シナリオ
- モバイルアプリケーション開発: ネットワーク帯域が限られるモバイル環境において、ペイロードサイズを最小限に抑え、レスポンス速度を向上させます。
- シングルページアプリケーション (SPA): React や Vue.js などで構築されたリッチなフロントエンドで、複数の関連オブジェクトのデータを一度に効率的に取得し、コンポーネントを描画します。
- マイクロサービスアーキテクチャ: 特定の機能を持つマイクロサービスが、Salesforce から必要最低限のデータセットを効率的に取得する際に利用します。
原理説明
GraphQL API の仕組みを理解する上で重要なコンセプトがいくつかあります。これらは従来の REST API とは異なる考え方に基づいています。
単一のエンドポイント
REST API が /services/data/vXX.X/sobjects/Account/{AccountId}
や /services/data/vXX.X/sobjects/Contact/{ContactId}
のように、リソースごとに異なるエンドポイントを持つのに対し、GraphQL API は通常、/services/data/vXX.X/graphql
という単一の Endpoint (エンドポイント) を使用します。すべてのデータ操作(取得、作成、更新、削除)は、この単一のエンドポイントに対する POST リクエストとして送信されます。
スキーマ駆動
GraphQL は厳密に型付けされたシステムであり、API の能力は Schema (スキーマ) によって定義されます。スキーマは、API でクエリ可能なすべてのデータ型、フィールド、リレーションシップ、そして実行可能な操作(クエリやミューテーション)を記述したものです。クライアントはこのスキーマを「イントロスペクションクエリ」によって取得できるため、API の構造を動的に理解し、利用可能なデータを探索することができます。これは API の自己文書化にも繋がり、開発効率を大きく向上させます。Salesforce GraphQL API のスキーマは、あなたの組織の標準オブジェクト、カスタムオブジェクト、およびそれらの項目を反映しています。
クエリとミューテーション
GraphQL の操作には、主に2つの種類があります。
- Query (クエリ): データの読み取り操作です。クライアントは JSON ライクな構文で、取得したいオブジェクト、フィールド、そして関連オブジェクトの階層構造を記述します。サーバーは、そのクエリの構造と完全に一致した構造の JSON データを返します。
- Mutation (ミューテーション): データの書き込み操作(作成、更新、削除)です。クエリと同様に、操作対象のデータと、操作後に返してほしいデータのフィールドを指定することができます。これにより、例えばレコードを作成した直後に、そのレコードの ID やシステム項目をレスポンスとして受け取ることが可能です。
このクライアント主導のアプローチにより、サーバー側の実装を変更することなく、フロントエンドのデータ要件の変更に柔軟に対応できるという大きなメリットが生まれます。
示例代码
ここでは、Salesforce の公式ドキュメントに記載されている例を基に、GraphQL クエリの具体的な使い方を見ていきましょう。以下の例では、「"United Oil" という名前で始まる取引先」と、その取引先に関連する「取引先責任者の ID、名前、電話番号」を一度のリクエストで取得します。
GraphQL クエリの例
query accountAndContacts($accountName: String) { uiapi { query { Account(where: { Name: { like: $accountName } }, first: 5) { edges { node { Id Name { value } Phone { value } Contacts(first: 10) { edges { node { Id Name { value } Phone { value } } } } } } } } } }
GraphQL 変数の例
{ "accountName": "United Oil%" }
コードの解説
query accountAndContacts(...)
: このクエリに `accountAndContacts` という名前を付けています。クエリに名前を付けることは、デバッグやサーバーサイドでのロギングに役立つベストプラクティスです。($accountName: String)
の部分で、このクエリが `accountName` という名前の文字列型の変数を受け取ることを定義しています。uiapi
: Salesforce の GraphQL API におけるトップレベルのエントリポイントです。すべてのクエリはここから始まります。query { Account(...) }
: データの読み取り操作を開始し、`Account` オブジェクトを対象とすることを宣言しています。where: { Name: { like: $accountName } }
: SOQL の `WHERE` 句に相当し、`Name` 項目が変数 `$accountName` の値に `like` (前方一致) するレコードをフィルタリングします。first: 5
: 取得する取引先レコードの最大数を5件に制限します。edges { node { ... } }
: これは GraphQL のカーソルベースのページネーションの標準的な形式(Relay スタイル)です。edges
はレコードのリストを表す配列で、各要素(edge)には実際のデータを含む `node` が含まれています。Id
,Name { value }
,Phone { value }
: 取得したい取引先の項目を指定しています。Salesforce GraphQL API では、多くのフィールドがvalue
やdisplayValue
などのプロパティを持つオブジェクトとして返されるため、Name { value }
のように記述する必要があります。Contacts(first: 10) { ... }
: これが GraphQL の最も強力な部分です。`Account` オブジェクトのクエリ内に、関連オブジェクトである `Contacts` のクエリをネストしています。これにより、各取引先に関連する取引先責任者を最大10件まで取得できます。REST API であれば、ここでもう一度別の API コールが必要になるところです。
このクエリを実行すると、サーバーはリクエストされた構造と全く同じ階層構造を持つ JSON レスポンスを返します。これにより、クライアントはレスポンスをパースしやすく、アプリケーションの状態管理が非常にシンプルになります。
注意事項
GraphQL API は非常に強力ですが、利用する際にはいくつかの注意点があります。
権限 (Permissions)
GraphQL API は、実行ユーザーの権限を完全に尊重します。オブジェクトレベルのセキュリティ、項目レベルのセキュリティ (FLS)、共有ルールなど、Salesforce のすべてのセキュリティモデルが適用されます。ユーザーがアクセス権を持たないオブジェクトや項目をクエリに含めても、そのデータはレスポンスに含まれないか、エラーが返されます。これは、GraphQL を利用してもセキュリティが損なわれることはないという重要な保証です。
API 制限 (API Limits)
GraphQL API のコールは、他の API コールと同様に、組織の「24時間あたりの合計 API リクエスト数」のガバナ制限にカウントされます。1回の GraphQL クエリは、その複雑さに関わらず、1回の API コールとして計上されます。これが、複数の REST コールを1回にまとめられる GraphQL の大きな利点です。
ただし、GraphQL 固有の制限も存在します。例えば、クエリの深さ、クエリあたりのノード数、一度にクエリできるオブジェクトの総数などです。これらの制限を超える複雑なクエリはエラーとなります。設計時には、過度に複雑なクエリを作成しないよう注意が必要です。
エラー処理 (Error Handling)
GraphQL API のエラー処理は、REST API とは少し異なります。REST API では、リクエストに問題があれば 4xx や 5xx といった HTTP ステータスコードが返されるのが一般的です。しかし GraphQL では、リクエストの一部が成功し、一部が失敗した場合でも、HTTP ステータスコードは 200 OK
を返すことがあります。
その代わり、レスポンスボディの JSON に data
キーと並んで errors
キーが含まれます。data
には成功した部分の結果が、errors
には失敗した部分のエラー詳細が配列として格納されます。統合エンジニアは、クライアント側の実装で、レスポンスに errors
配列が存在するかどうかを必ずチェックし、適切に処理する必要があります。
まとめとベストプラクティス
Salesforce GraphQL API は、特にモダンなウェブアプリケーションやモバイルアプリケーションとの連携において、従来の REST API が抱える課題を解決する強力なツールです。クライアントが必要なデータを一度のリクエストで効率的に取得できる能力は、パフォーマンスの向上と開発体験の改善に大きく貢献します。
ベストプラクティス
- 適切なツールを適切な場所で使う: GraphQL は、複数の関連オブジェクトにまたがる複雑なデータ読み取りに最適です。しかし、大量のデータを一括でロードまたはエクスポートするなら Bulk API、単一レコードの単純な CRUD 操作なら REST API の方がシンプルで適している場合もあります。常に要件に合った最適な API を選択してください。
- クエリに名前を付ける: サンプルコードで示したように、
query MyQueryName { ... }
のように、すべてのクエリとミューテーションにユニークな名前を付けましょう。これにより、サーバーサイドのログや分析ツールで特定の操作を追跡しやすくなります。 - 変数を利用する: クエリ内に直接値をハードコーディングするのではなく、変数を利用して動的なクエリを作成します。これにより、クエリの再利用性が高まり、クライアント側のコードがクリーンになります。
- 部分的なエラーを考慮した実装: クライアントアプリケーションでは、レスポンスに
errors
配列が含まれている可能性を常に考慮し、ユーザーに適切なフィードバックを提供できるようエラーハンドリングを堅牢に実装してください。 - スキーマイントロスペクションを活用する: 開発時には、GraphiQL のようなツールを使ってスキーマを探索し、利用可能な型やフィールドを確認することで、効率的にクエリを構築できます。
統合エンジニアとして、私たちは常にシステム間のデータフローを最適化する責任を負っています。Salesforce GraphQL API は、そのための強力な選択肢の一つです。この API の特性を正しく理解し、活用することで、より応答性が高く、効率的で、保守しやすい連携ソリューションを構築できるでしょう。
コメント
コメントを投稿