概要とビジネスシーン
Salesforce GraphQL API は、クライアントが必要なデータを単一のリクエストで正確に取得できる、柔軟かつ強力なデータフェッチングメカニズムを提供し、過剰なデータ取得(over-fetching)や不足(under-fetching)を解消します。
実際のビジネスシーン
シーンA - eコマース業界:あるオンラインストアのモバイルアプリケーションは、商品の詳細表示ページで、商品情報、在庫状況、顧客レビュー、関連商品といった複数のSalesforceオブジェクトや外部システムからのデータを集約して表示する必要があります。
- ビジネス課題:従来のREST APIでは、これらの情報を取得するために複数のエンドポイントへのリクエストが必要で、モバイル環境でのネットワーク遅延とデータ消費が問題となっていました。また、バックエンドで取得した全データの中からモバイル表示に必要な部分だけを抽出する処理が複雑でした。
- ソリューション:Salesforce GraphQL API を導入し、必要な全てのデータを1回のクエリで取得するように設計しました。これにより、クライアントサイドで取得するデータの粒度を細かく制御できるようになりました。
- 定量的効果:モバイルアプリの商品詳細ページのロード時間が平均で30%短縮され、ユーザーエクスペリエンスが大幅に向上しました。また、APIリクエスト回数が80%削減され、バックエンドの負荷も軽減されました。
シーンB - 顧客サービス業界:顧客サービス部門では、顧客からの問い合わせに対して、顧客情報、過去の注文履歴、関連するサポートケース、契約情報などを統合した「顧客360度ビュー」をエージェント用コンソールに表示する必要があります。
- ビジネス課題:異なるSalesforceオブジェクト(Account, Contact, Order, Case)に分散している情報を取得するために、複数のSOQLクエリやREST APIコールが必要でした。これにより、コンソールの表示に時間がかかり、エージェントの生産性が低下していました。
- ソリューション:GraphQL API を利用して、単一のクエリでこれらの関連する全てのデータを取得するインターフェースを開発しました。顧客IDを基点として、ネストされた関連データを効率的にフェッチできるようになりました。
- 定量的効果:エージェントコンソールでの顧客情報表示時間が平均で25%改善され、エージェントの顧客対応時間が平均15秒短縮されました。これにより、1日あたりの処理件数が増加し、顧客満足度も向上しました。
技術原理とアーキテクチャ
Salesforce GraphQL API は、基盤となる UI API(User Interface API) の上に構築されており、Salesforceオブジェクトデータへのアクセスを提供します。クライアントからの単一のGraphQLクエリリクエストは、SalesforceのGraphQLエンジンによって解析され、内部的に適切なSOQLクエリに変換されてSalesforceデータベースからデータを取得し、要求された構造に整形されてJSON形式でクライアントに返されます。
主要コンポーネントと依存関係
- スキーマ(Schema):Salesforceオブジェクトとそれらのフィールド、リレーション、およびデータ型を定義します。クライアントはこのスキーマに基づいてクエリを作成します。GraphQL APIはUI APIをベースとしているため、Salesforceのオブジェクトやフィールドが自動的にGraphQLの型として公開されます。
- クエリ(Query):データの読み取り操作を定義します。クライアントは必要なフィールドと関連オブジェクトをネストして指定できます。
- ミューテーション(Mutation):データの作成、更新、削除(CRUD操作)を定義します。現在のSalesforce GraphQL API(UI APIベース)は主にデータの読み取りに焦点を当てており、ミューテーションは一部限定的です。
- リゾルバー(Resolver):クエリ内の各フィールドに対応するデータ取得ロジックです。Salesforce GraphQL APIでは、これらのリゾルバーはSalesforceプラットフォームによって内部的に自動生成・管理され、開発者が明示的に記述する必要はありません。
データフロー
| フェーズ | 説明 | 担当コンポーネント |
|---|---|---|
| 1. クライアント要求 | GraphQLクエリを含むHTTP POSTリクエストをSalesforceのGraphQLエンドポイントへ送信します。 | クライアントアプリケーション |
| 2. クエリ解析と検証 | SalesforceのGraphQLエンジンが受信したクエリを解析し、スキーマ定義と照合して有効性を検証します。 | Salesforce GraphQLエンジン |
| 3. データフェッチ | 検証されたクエリは内部的にSOQLクエリなどに変換され、Salesforceデータベースから必要なデータを効率的に取得します。 | Salesforceデータベース、UI API |
| 4. データ整形 | 取得された生データは、クライアントのクエリで要求されたJSON構造に正確に整形されます。 | Salesforce GraphQLエンジン |
| 5. レスポンス | 整形されたJSONデータがHTTPレスポンスとしてクライアントに返却されます。エラーがある場合は、errors配列に含まれます。 |
Salesforce GraphQLエンジン |
ソリューション比較と選定
| ソリューション | 適用シーン | パフォーマンス | Governor Limits | 複雑度 |
|---|---|---|---|---|
| GraphQL API |
|
過剰フェッチを防ぎ、ネットワーク負荷を軽減するため、多くの場合で最適 | クエリ複雑度スコア(デフォルト10,000)、UI APIコール制限。一度に取得できるレコード数に制限(例: first: 200) |
単一エンドポイントとスキーマ駆動でシンプルなクエリ。学習コストはRESTより高いが、長期的な開発効率は向上 |
| REST API (SObject, Query, Composite) |
|
複数のリクエストが必要な場合があり、Over-fetchingが発生しやすい | APIコール制限(組織エディションに基づく)、Composite APIはサブクエリ数に制限 | シンプルで広く利用されており、ツールも豊富。複雑なデータ取得では複数のリクエストが必要になり、クライアント側のデータ結合が複雑化 |
| SOQL (Apex REST, Tooling API) |
|
Apex内で最適化されたクエリが可能。APIとして公開する場合は、ネットワークオーバーヘッドがある | SOQLクエリの行数制限(50,000)、CPU時間、ヒープサイズなどApexのGovernor Limitsに準拠 | Apex開発スキルが必要。柔軟性が高いが、クライアントからの直接アクセスには向かない場合が多い |
GraphQL API を使用すべき場合
- ✅ 複数のSalesforceオブジェクトや関連データから複雑なビューを構築したい場合:例えば、顧客情報、関連するケース、注文履歴、アセットなど、異なるオブジェクトのデータを統合して表示するユースケース。
- ✅ モバイルアプリやSPA(Single Page Application)など、ネットワーク効率とクライアント側の柔軟性が重要な場合:必要なデータのみを最小限のネットワークラウンドトリップで取得し、アプリケーションのパフォーマンスと応答性を向上させたい。
- ✅ 頻繁にデータ取得要件が変化するフロントエンド開発:スキーマ駆動であるため、フロントエンドの変更に合わせてクエリを調整するだけで、バックエンドの変更を最小限に抑えられます。
- ❌ 非常にシンプルな単一レコードのCRUD操作で、パフォーマンス要件が低く、既存REST APIで十分な場合:GraphQLの導入コストとメリットが見合わない可能性があります。
- ❌ 大規模なバッチ処理やファイルアップロード、ストリーミングなど、GraphQLの目的と異なるデータ処理が求められるケース:これらの用途には、Batch ApexやStreaming APIなど、Salesforceが提供する他の専用APIがより適しています。
実装例
Salesforce GraphQL API は、主にUI API の GraphQL エンドポイントを通じて利用されます。以下に、Apex から Salesforce GraphQL API を呼び出し、Account オブジェクトから特定のフィールドと関連する Contact オブジェクトのデータを取得するコード例を示します。
public class SalesforceGraphQLClient {
// Salesforce GraphQL API エンドポイント
// UI APIのGraphQLエンドポイントは `/services/data/vXX.0/graphql` です。
private static final String GRAPHQL_ENDPOINT = URL.getOrgDomainUrl().toExternalForm() + '/services/data/v59.0/graphql';
/**
* Accountと関連ContactのデータをGraphQL APIで取得するメソッド
* @return 取得したJSON文字列
*/
public static String getAccountWithContactsData() {
// GraphQL クエリの定義
// UI API の GraphQL エンドポイントでは、`uiapi` ルート要素の下にクエリを記述します。
// `query` フィールドはオブジェクトのコレクションを、`record` フィールドは単一のレコードをフェッチします。
// `first: 5` は最初の5件のレコードを取得することを意味します。
// `edges { node { ... } }` は GraphQL の標準的な接続(Connection)パターンです。
String graphqlQuery = '{ "query": "{ uiapi { query { Account (first: 5) { edges { node { Id Name AnnualRevenue (format: RAW) Industry Contacts (first: 2) { edges { node { Id Name Email Phone } } } } } } } } }" }';
HttpRequest req = new HttpRequest();
req.setEndpoint(GRAPHQL_ENDPOINT);
req.setMethod('POST');
req.setHeader('Content-Type', 'application/json');
req.setHeader('Authorization', 'Bearer ' + UserInfo.getSessionId()); // セッションIDを使用して認証
req.setBody(graphqlQuery); // クエリをリクエストボディに設定
req.setTimeout(120000); // タイムアウトを120秒に設定 (ミリ秒単位)
try {
Http http = new Http();
HttpResponse res = http.send(req); // HTTPリクエストを送信
// レスポンスのステータスコードを確認
if (res.getStatusCode() == 200) {
System.debug('GraphQL API Response: ' + res.getBody());
return res.getBody(); // レスポンスボディを返す
} else {
System.debug('GraphQL API Error: ' + res.getStatusCode() + ' - ' + res.getBody());
throw new CalloutException('GraphQL API Callout Failed: ' + res.getStatusCode() + ' - ' + res.getBody());
}
} catch (Exception e) {
System.debug('Exception during GraphQL API Call: ' + e.getMessage());
throw new CalloutException('Exception in GraphQL API Call: ' + e.getMessage());
}
}
/**
* 実行例 (匿名実行ウィンドウまたはLWCのApexメソッドから呼び出し)
* System.debug(SalesforceGraphQLClient.getAccountWithContactsData());
*/
}
上記のコードは、SalesforceのUI APIが提供するGraphQLエンドポイントに対してHTTP POSTリクエストを送信するApexクラスです。この例では、最初5件のAccountレコードと、それぞれのAccountに関連する最初の2件のContactレコードのId、Name、AnnualRevenue(RAW形式)、Industry、Email、Phoneフィールドを取得しています。
GRAPHQL_ENDPOINT: Salesforceの現在のインスタンスに対するGraphQL APIのエンドポイントを定義します。SalesforceのUI APIのバージョンは常に最新のものを使用するようにしてください(例: v59.0)。graphqlQuery: ここにGraphQLクエリをJSON文字列として記述します。uiapiルートの下に、query演算子を使ってAccountオブジェクトをクエリしています。ContactsはAccountの子リレーションとしてネストされています。HttpRequest: HTTP POSTメソッドを使用し、Content-Typeヘッダーをapplication/jsonに設定します。認証には現在のユーザーのセッションIDをAuthorizationヘッダーに設定します。HttpResponse: リクエスト送信後、レスポンスのステータスコードを確認し、エラーがない場合はレスポンスボディを返します。GraphQL APIはエラーが発生してもHTTPステータスコード200を返す場合があるため、レスポンスボディ内のerrorsフィールドも確認することが重要です。
この実装は、開発者がSalesforceのサーバーサイドでカスタムロジックを必要とする場合に特に有用です。クライアントサイドJavaScript(LWCなど)から直接GraphQL APIを呼び出すことも可能ですが、CORS(Cross-Origin Resource Sharing)設定やセキュリティトークンの管理が必要になります。
注意事項とベストプラクティス
権限要件
- UI APIアクセス:GraphQL APIはUI APIをベースとしているため、ユーザーはUI APIにアクセスできる必要があります。通常、これは標準プロファイルや権限セットに含まれていますが、カスタムプロファイル/権限セットでは明示的に有効にする必要がある場合があります。
- オブジェクトとフィールドレベルセキュリティ:クエリでアクセスするすべてのSalesforceオブジェクトおよびフィールドに対して、ユーザーが少なくとも読み取り(Read)権限を持っている必要があります。権限セット(Permission Set)を使用して、必要なオブジェクトとフィールドのアクセス権を付与してください。
- コールアウトの許可:ApexからGraphQL APIを呼び出す場合、リモートサイト設定(Remote Site Setting)でSalesforceのドメイン(例:
*.salesforce.com)を許可する必要があります。
Governor Limits(2025年最新版に基づく)
Salesforce GraphQL API は UI API の制限に準拠します。特に以下の点に注意してください。
- クエリ複雑度スコア:各GraphQLクエリには複雑度スコアが計算され、デフォルトで最大 10,000 点という制限があります。このスコアは、クエリで要求されるフィールドの数、ネストの深さ、リレーションの数、およびクエリ対象のレコード数によって増加します。複雑なクエリや多数の関連レコードを取得しようとすると、この制限に達する可能性があります。
- レコード数制限:単一のクエリで各接続(connection)からフェッチできるレコードの最大数は 200 件です(例:
first: 200)。これを超えるデータを取得するには、ページネーション(after引数)を使用する必要があります。 - APIコール制限:Salesforce組織のエディションに基づいたUI API全体のAPIコール制限(例: Enterprise Editionで1日あたり15,000 + ライセンス数×1,000回)にカウントされます。GraphQL APIはUI APIのエンドポイントであるため、これらの制限を超えないように注意が必要です。
エラー処理
- レスポンスボディ内の
errorsフィールド:GraphQL APIは、クエリ実行中にエラーが発生した場合でも、HTTPステータスコード 200 OK を返すことがあります。この場合、レスポンスボディのJSONにerrorsという配列が含まれ、エラーの詳細が記述されます。常にこのerrorsフィールドの存在をチェックし、適切に処理する必要があります。 - 一般的なエラーコード:
GRAPHQL_VALIDATION_ERROR:クエリがスキーマに準拠していない場合。ACCESS_DENIED:ユーザーにデータへのアクセス権限がない場合。INTERNAL_SERVER_ERROR:Salesforce側で予期せぬエラーが発生した場合。LIMIT_EXCEEDED:Governor Limits(複雑度スコアなど)を超過した場合。
- リトライ戦略:一時的なネットワーク問題やサービス中断に備え、指数バックオフ(Exponential Backoff)を用いたリトライ戦略を実装することを検討してください。
パフォーマンス最適化
- 必要なフィールドのみ選択:過剰なデータフェッチ(Over-fetching)を防ぐため、クエリでは本当に必要なフィールドのみを指定してください。これにより、ネットワーク帯域幅の節約と、Salesforce側でのデータ処理負荷の軽減につながります。
- クエリ複雑度スコアの最適化:可能な限りクエリを簡素化し、ネストの深さやリレーションの数を最小限に抑えることで、Governor Limitsに達するリスクを減らし、パフォーマンスを向上させます。開発者コンソールやPostmanなどのツールでクエリを実行し、複雑度スコアを評価してください。
- ページネーションの活用:大量のレコードを取得する必要がある場合は、
firstおよびafter引数を使用してページネーションを実装し、一度に取得するレコード数を制限してください。これにより、ネットワーク負荷が分散され、応答時間が向上します。 - クライアントサイドキャッシュ:取得したデータをクライアントサイドでキャッシュすることで、頻繁にアクセスされるデータの再フェッチを避け、アプリケーションの応答性を高めることができます。
よくある質問 FAQ
Q1:Salesforce GraphQL API と REST API のどちらを使うべきですか?
A1:要件に依存します。GraphQL API は、複数の関連オブジェクトから複雑なデータを効率的に取得したい場合、特にモバイルアプリやSPAのようにネットワーク効率が重要なクライアントに適しています。REST API は、シンプルで単一オブジェクトのCRUD操作、または既存のRESTエコシステムとの連携に適しており、実装が比較的容易です。
Q2:Salesforce GraphQLクエリのデバッグ方法は?
A2:Apexからのコールアウトの場合は、開発者コンソールのデバッグログでHTTPリクエストとレスポンスの内容を確認できます。また、PostmanやInsomniaなどのAPIクライアントツールを使用し、GraphQLエンドポイントに直接クエリを送信してレスポンスとエラーを詳細に調査するのが最も効果的です。
Q3:GraphQL APIのパフォーマンスを監視するには?
A3:SalesforceのAPI UsageレポートでAPIコール総数を確認できます。より詳細な監視には、カスタムログを実装してクエリの応答時間やエラー率を記録するか、外部のAPM(Application Performance Management)ツールをSalesforceのAPIゲートウェイと連携させることを検討してください。特にクエリ複雑度スコアの傾向を監視し、制限を超過しないように注意することが重要です。
まとめと参考資料
Salesforce GraphQL API は、Salesforceデータをクライアントアプリケーションに効率的に提供するための強力なツールです。過剰なデータフェッチを防ぎ、開発の柔軟性を高め、ネットワークパフォーマンスを最適化する能力は、特に複雑なUIを持つアプリケーションやモバイル環境において大きな価値を発揮します。スキーマ駆動であることによる型の安全性と、単一エンドポイントからの柔軟なデータ取得は、現代のアプリケーション開発において重要なメリットです。Governor Limits や権限要件を理解し、ベストプラクティスに従うことで、その真価を最大限に引き出すことができます。
公式リソース
- 📖 公式ドキュメント:Salesforce UI API Developer Guide (GraphQL API)
- 🎓 Trailhead モジュール:Integrate Data with the Salesforce API (GraphQLに特化したモジュールはまだ少ないため、API統合全般の学習パス)
- 🔧 関連 GitHub サンプル:Salesforce公式のGraphQLクライアントライブラリは提供されていませんが、HTTPクライアントを使用するサンプルは上記の公式ドキュメントで参照可能です。
コメント
コメントを投稿