背景と応用シナリオ
Salesforce 開発者として、私たちは常に外部システムとの連携や、複雑なビジネスロジックを効率的に実装する方法を模索しています。従来の連携方法では、一連のビジネスプロセスを完了させるために、複数の API コールを順番に実行する必要がありました。例えば、新規顧客を登録するシナリオを考えてみましょう。
- 取引先 (Account) を作成する (1回目の API コール)
- 作成された取引先の ID を取得する
- その取引先 ID を使用して、関連する取引先責任者 (Contact) を作成する (2回目の API コール)
- さらに、その取引先に関連する商談 (Opportunity) を作成する (3回目の API コール)
このアプローチにはいくつかの課題があります。まず、ネットワークレイテンシー (Network Latency) です。各 API コールは個別の HTTP リクエストとレスポンスを伴うため、ネットワークの往復時間が積み重なり、全体の処理時間が長くなります。次に、API 制限 (API Limits) の問題です。Salesforce には24時間あたりの API コール数に上限があり、このような「おしゃべりな (chatty)」連携は、貴重な API コール数を急速に消費してしまいます。最後に、トランザクション管理 (Transaction Management) の複雑さです。もし3番目の「商談の作成」でエラーが発生した場合、すでに作成済みの取引先と取引先責任者はどうなるでしょうか?手動でロールバック処理を実装しなければ、データの一貫性が損なわれる可能性があります。
これらの課題を解決するために Salesforce が提供するのが Composite API (複合API) です。Composite API は、最大25個の独立した REST API リクエストを単一の HTTP コールにまとめることができる強力なツールです。これにより、ネットワークの往復回数を劇的に削減し、API 制限の消費を抑え、さらにアトミックなトランザクション処理を実現することが可能になります。
応用シナリオとしては、以下のようなケースが考えられます。
- カスタム UI の実装: Single Page Application (SPA) などで、ユーザーが「保存」ボタンを一度クリックするだけで、複数の関連オブジェクト(例:注文と注文品目)を一度に作成・更新する。
- 外部システム連携: ERP システムから送られてくる顧客マスターと初期契約情報を、Salesforce 上で取引先、取引先責任者、契約オブジェクトとして一度のトランザクションで作成する。
- データ移行の補助: 複雑なリレーションを持つ少量のデータを、依存関係を維持しながら一括で投入する。
原理説明
Composite API の核心的な原理は「リクエストの集約」と「依存関係の解決」です。開発者は、実行したい一連の API リクエストを JSON 形式のペイロードとして構築し、それを単一の POST
リクエストとして /services/data/vXX.X/composite
エンドポイントに送信します。
このリクエストボディの JSON には、主に2つの重要なプロパティがあります。
1. allOrNone
これはトランザクションの挙動を制御するブール値のフラグです。
true
の場合: すべてのサブリクエストが成功した場合にのみ、全体のトランザクションがコミットされます。一つでもサブリクエストが失敗すると、それ以前に成功したサブリクエストもすべてロールバックされ、データベースには一切変更が加えられません。これにより、原子性 (Atomicity) が保証されます。false
の場合: 各サブリクエストは独立して実行されます。一部が失敗しても、成功した他のサブリクエストはコミットされます。これは、個々の処理が互いに独立している場合に適しています。
2. compositeRequest
これは、実行したい個々の API リクエスト(サブリクエスト)の配列です。各サブリクエストオブジェクトには、以下のプロパティが含まれます。
- method: HTTP メソッド (
GET
,POST
,PATCH
,DELETE
など)。 - url: 標準の REST API の URL (例:
/services/data/v58.0/sobjects/Account
)。 - referenceId: このサブリクエストを後続のサブリクエストから参照するためのユニークな識別子です。これが Composite API の最も強力な機能の一つです。
- body:
POST
やPATCH
リクエストで使用するリクエストボディです。
特に重要なのが referenceId
を使った依存関係の解決です。例えば、最初のサブリクエストで新しい取引先を作成し、その referenceId
を "newAccount"
としたとします。後続のサブリクエストで、この取引先に関連する取引先責任者を作成する場合、取引先責任者の AccountId
項目に、先ほど作成した取引先の ID を指定する必要があります。Composite API では、これを "@{newAccount.id}"
という特殊な構文で参照できます。これにより、最初の API コールのレスポンスを待ってその ID を抽出し、次の API コールに渡す、という処理をクライアント側で行う必要がなくなります。すべての依存関係は Salesforce サーバーサイドで解決されるため、非常に効率的です。
レスポンスも同様に集約された形式で返されます。compositeResponse
という配列が含まれており、その中の各要素が、リクエストの compositeRequest
配列の各サブリクエストに順番に対応した結果となっています。
示例代码
ここでは、Salesforce の公式ドキュメントで紹介されている最も代表的な例である「新しい取引先と、それに関連する取引先責任者を1つのトランザクションで作成する」コードを示します。この例では、トランザクションの原子性を保証するために allOrNone
を true
に設定します。
リクエストの例
以下の JSON ペイロードを /services/data/v58.0/composite
エンドポイントに POST
します。
{ "allOrNone" : true, "compositeRequest" : [{ "method" : "POST", "url" : "/services/data/v58.0/sobjects/Account", "referenceId" : "refAccount", "body" : { "Name" : "Salesforce" } },{ "method" : "POST", "url" : "/services/data/v58.0/sobjects/Contact", "referenceId" : "refContact", "body" : { "LastName" : "Benioff", "AccountId" : "@{refAccount.id}" } }] }
コードの詳細な注釈
"allOrNone" : true
: このリクエスト全体がアトミックなトランザクションであることを宣言しています。取引先の作成が成功しても、取引先責任者の作成が何らかの理由で失敗した場合、取引先の作成も自動的にロールバックされます。"compositeRequest" : [...]
: 実行するサブリクエストの配列です。- 最初のサブリクエスト:
"method" : "POST"
: 新規レコードを作成します。"url" : "/services/data/v58.0/sobjects/Account"
: 取引先オブジェクトに対する操作です。"referenceId" : "refAccount"
: このリクエストに「refAccount」という参照 ID を割り当てます。これはこの Composite リクエスト内でユニークであれば任意の文字列で構いません。"body" : { "Name" : "Salesforce" }
: 作成する取引先の名前を指定します。
- 2番目のサブリクエスト:
"method" : "POST"
: 同様に新規レコードを作成します。"url" : "/services/data/v58.0/sobjects/Contact"
: 取引先責任者オブジェクトに対する操作です。"referenceId" : "refContact"
: このリクエストに「refContact」という参照 ID を割り当てます。"body" : { ... }
: 作成する取引先責任者の詳細です。"AccountId" : "@{refAccount.id}"
: ここが最も重要な部分です。refAccount
という参照 ID を持つサブリクエストの結果(この場合は作成された取引先レコード)のid
属性を参照しています。この構文により、Salesforce は内部で最初のサブリクエストで作成された取引先の ID を取得し、この取引先責任者のAccountId
に自動的に設定します。
レスポンスの例
上記のリクエストが成功した場合、以下のようなレスポンスが返されます。
{ "compositeResponse" : [{ "body" : { "id" : "001xx000003DHPF", "success" : true, "errors" : [ ] }, "httpHeaders" : { "Location" : "/services/data/v58.0/sobjects/Account/001xx000003DHPF" }, "httpStatusCode" : 201, "referenceId" : "refAccount" },{ "body" : { "id" : "003xx000003DHPG", "success" : true, "errors" : [ ] }, "httpHeaders" : { "Location" : "/services/data/v58.0/sobjects/Contact/003xx000003DHPG" }, "httpStatusCode" : 201, "referenceId" : "refContact" }] }
レスポンスの compositeResponse
配列は、リクエストのサブリクエストと同じ順序で結果を格納しています。各要素には、HTTP ステータスコード (httpStatusCode
)、レスポンスボディ (body
)、そしてリクエスト時に指定した referenceId
が含まれており、どのリクエストに対する結果なのかを簡単に特定できます。
注意事項
Composite API は非常に強力ですが、利用する際にはいくつかの点に注意する必要があります。
- 権限 (Permissions): Composite API を実行するユーザーは、リクエストに含まれるすべてのサブリクエストを実行するために必要なオブジェクトレベルおよび項目レベルのセキュリティ権限を持っている必要があります。API は Salesforce の標準的な共有ルールと権限モデルに完全に従います。
- API 制限 (API Limits):
- コール数: Composite API リクエスト全体で、組織の API コール上限に対して 1コール としてカウントされます。これは最大の利点の一つです。
- サブリクエスト数: 1つの Composite API リクエストに含めることができるサブリクエストの最大数は 25個 です。
- データ量: Composite API は大量のデータを一括でロード・更新する目的には設計されていません。その用途には、Bulk API を使用するべきです。Composite API は、あくまで複雑なトランザクションを効率的に処理するためのものです。
- エラー処理 (Error Handling):
allOrNone: true
の場合: いずれかのサブリクエストが失敗すると、レスポンス全体の HTTP ステータスコードは200 OK
となりますが、失敗したサブリクエストのレスポンスボディにエラー詳細が含まれ、httpStatusCode
は4xx
などのエラーコードになります。クライアント側では、compositeResponse
配列をループして各サブリクエストの結果を個別に確認する必要があります。allOrNone: false
の場合: 各サブリクエストの成否を個別に確認し、失敗した処理に対する補完ロジック(リトライやエラー通知など)をクライアント側で実装する必要があります。
- サポートされる操作: sObject の CRUD 操作やクエリ (Query) など、多くの基本的な REST API リソースがサポートされていますが、すべての REST API エンドポイントがサブリクエストとして利用できるわけではありません。利用前にドキュメントでサポート範囲を確認することが重要です。
まとめとベストプラクティス
Composite API は、Salesforce 開発者が連携処理を構築する上で欠かせないツールです。複数の API コールを一つにまとめることで、パフォーマンスを向上させ、API 制限の消費を抑え、データの一貫性を保つための堅牢なトランザクション管理を提供します。
以下に、開発者としてのベストプラクティスをまとめます。
- ビジネスプロセスをアトミックに保つ: 互いに強く依存し、一連の処理として成功または失敗すべき操作には、必ず
allOrNone: true
を使用します。これにより、データインテグリティが保たれます。 - 適切なツールを選択する: 複雑な依存関係を持つ少〜中程度のレコードセットのトランザクションには Composite API を、数千件以上の大量データの処理には Bulk API を、単純な単一レコードの操作には標準の sObject REST API を、と用途に応じて API を使い分けましょう。
referenceId
を最大限に活用する: レコード間のリレーションを構築する際には、referenceId
を積極的に利用してください。これにより、不要なクエリコールを排除し、コードをシンプルかつ効率的に保つことができます。- 堅牢なクライアント側エラーハンドリングを実装する: API からのレスポンスは常に成功するとは限りません。
compositeResponse
配列を適切に解析し、各サブリクエストの成功・失敗を判定し、ユーザーに適切なフィードバックを返す、あるいはログに記録する処理を必ず実装してください。
Composite API を正しく理解し活用することで、より応答性が高く、効率的で、信頼性のある Salesforce アプリケーションや連携ソリューションを構築することができるでしょう。