はじめに:統合エンジニアの視点から
Salesforce統合エンジニアとして、私は日々、Salesforceと外部システム(ERP、マーケティングオートメーション、カスタムアプリケーションなど)をシームレスに連携させるという課題に取り組んでいます。これらの連携を設計・構築する上で最も重要な考慮事項の一つが、パフォーマンスと信頼性です。特に、複数の関連データを一度に作成・更新する必要があるシナリオでは、従来のアプローチ、つまり個別のAPIコールを何度も送信する方法では、ネットワークの往復回数が増え、顕著なNetwork Latency(ネットワーク遅延)が発生してしまいます。
また、一連の処理が全体として成功するか失敗するかのいずれかであることを保証する、いわゆるAtomic(アトミック)な操作を実現することも、データ整合性を保つ上で極めて重要です。例えば、「取引先を作成し、その直後にその取引先に紐づく取引先責任者を作成する」という一連の処理で、取引先責任者の作成に失敗した場合、中途半端に作成された取引先だけが残ってしまうのは避けたい状況です。
このような課題を解決するためにSalesforceが提供している強力なツールが、Composite API(複合API)です。この記事では、統合エンジニアの視点から、Composite APIがどのようにして連携処理を効率化し、信頼性を高めるのか、その原理から具体的な実践方法、注意点までを徹底的に解説します。
背景と適用シナリオ
Composite APIは、複数の独立したREST APIリクエストを単一のHTTPリクエストにまとめることができる強力な機能です。これにより、クライアントとサーバー間の通信回数を劇的に削減できます。統合エンジニアとして、私は以下のようなシナリオでComposite APIの活用を強く推奨します。
シナリオ1:関連レコードの一括作成
課題:外部の顧客管理システムから新規顧客情報が連携される際、Salesforce内に「取引先」、「取引先責任者」(複数名)、そして「商談」を一度に作成する必要があるとします。これを個別のAPIコールで行う場合、最低でも3回以上(取引先責任者が増えればさらに多く)のAPIリクエストが必要になります。各リクエストにはネットワーク遅延が伴い、全体の処理時間が長くなります。
解決策:Composite APIを使用すれば、取引先の作成、取引先責任者の作成、商談の作成という3つのリクエストを1つのJSONペイロードにまとめて送信できます。さらに、最初の「取引先作成」リクエストの結果(新しく採番された取引先ID)を、後続の「取引先責任者作成」や「商談作成」リクエストの中で動的に参照することができるため、関連性の高いレコード群を一度の通信で、整合性を保ちながら作成することが可能です。
シナリオ2:アトミックなトランザクションの保証
課題:ECサイトで注文が確定した際に、Salesforceに「注文」オブジェクトと「注文品目」オブジェクトのレコードを作成する連携処理を考えます。注文品目の作成中に何らかのエラー(例えば、必須項目が不足しているなど)が発生した場合、親である注文レコードだけが作成されてしまうと、データに不整合が生じます。
解決策:Composite APIのallOrNone
パラメータをtrue
に設定することで、リクエスト全体を単一のトランザクションとして扱うことができます。これにより、もし1つでもSubrequest(サブリクエスト)が失敗した場合、そのトランザクション内で行われたすべてのデータベース操作が自動的にロールバックされます。つまり、「注文と注文品目がすべて正常に作成される」か「何も作成されない」かのどちらかの状態が保証され、データの整合性が維持されます。
原理の説明
Composite APIの核となるコンセプトは、「複数のAPIコールを一つのリクエストボディに集約し、サーバー側でそれらを順番に実行させる」という点にあります。この集約されたリクエストは、JSON形式で構成されます。
リクエストの構造
Composite APIへのリクエストは、compositeRequest
というキーを持つJSONオブジェクトの配列で構成されます。各オブジェクトが、個別のAPIコールに相当するサブリクエストです。
- allOrNone: (Boolean)
true
に設定すると、いずれかのサブリクエストが失敗した場合に、それ以前に成功したサブリクエストの操作もすべてロールバックされます。false
に設定すると、失敗したサブリクエストがあっても、成功したものはコミットされます。 - compositeRequest: (Array) 実行したいサブリクエストの配列です。各サブリクエストオブジェクトは以下の要素を持ちます。
- method: HTTPメソッド(例: "POST", "GET", "PATCH")。
- url: SObjectの標準REST APIエンドポイント(例: "/services/data/v58.0/sobjects/Account")。バージョン指定子を含みます。
- referenceId: このサブリクエストを一意に識別するためのIDです。後続のサブリクエストからこのリクエストの結果を参照するために使用します。
- body: POSTやPATCHメソッドで使用するリクエストボディ(例: 作成するレコードの項目と値)。
サブリクエスト間の依存関係
Composite APIの最も強力な機能の一つが、サブリクエスト間でデータを連携できることです。これはReference ID(参照ID)を用いて実現されます。
例えば、1番目のサブリクエストで取引先を作成し、そのreferenceId
を "newAccount" としたとします。2番目のサブリクエストでその取引先に紐づく取引先責任者を作成したい場合、取引先責任者のAccountId
項目に、1番目のサブリクエストの結果(新しく作成された取引先のID)を指定する必要があります。これは、"@{newAccount.id}"
という特殊な構文で参照できます。
このように、前のステップの実行結果を動的に次のステップの入力として利用できるため、複雑な依存関係を持つ一連の操作を、単一のAPIコールで完結させることができます。
レスポンスの構造
レスポンスもリクエストと同様にJSON形式で返され、compositeResponse
というキーを持つ配列が含まれています。この配列の要素は、リクエストのcompositeRequest
配列の各サブリクエストに1対1で対応しており、同じ順序で返されます。
各レスポンス要素には、httpStatusCode
(例: 201 Created)、body
(成功した場合はレコードIDなど、失敗した場合はエラー情報)、そしてリクエストで指定したreferenceId
が含まれます。これにより、どのサブリクエストが成功し、どれが失敗したのかを容易に判別し、適切な後続処理を行うことができます。
サンプルコード
ここでは、Salesforce公式ドキュメントに記載されている典型的な例として、「新しい取引先を作成し、その直後にその取引先に関連する取引先責任者を作成する」Composite APIリクエストを見てみましょう。
リクエスト例
以下のJSONは、allOrNone
をtrue
に設定し、取引先と取引先責任者の作成を単一のトランザクションとして実行するリクエストボディです。
{ "allOrNone" : true, "compositeRequest" : [{ "method" : "POST", "url" : "/services/data/v58.0/sobjects/Account", "referenceId" : "refAccount", "body" : { "Name" : "Sample Account" } },{ "method" : "POST", "url" : "/services/data/v58.0/sobjects/Contact", "referenceId" : "refContact", "body" : { "LastName" : "Smith", "AccountId" : "@{refAccount.id}" } }] }
コードの解説
- 1行目:
"allOrNone" : true
- このリクエスト全体がアトミックなトランザクションであることを宣言しています。もし取引先責任者の作成に失敗すれば、作成された取引先もロールバックされます。 - 2行目:
"compositeRequest" : [...]
- 実行するサブリクエストの配列を開始します。 - 4-8行目: 最初のサブリクエストです。
"method" : "POST"
: 新規レコードを作成します。"url" : "..."
: 取引先オブジェクトのエンドポイントを指定します。"referenceId" : "refAccount"
: このリクエストに "refAccount" という参照IDを付けます。"body" : { "Name" : "Sample Account" }
: 作成する取引先の名前を指定します。
- 9-16行目: 2番目のサブリクエストです。
"method" : "POST"
,"url" : "..."
,"referenceId" : "refContact"
: 同様に、取引先責任者を作成するための設定です。"AccountId" : "@{refAccount.id}"
: ここが最も重要な部分です。refAccount
という参照IDを持つサブリクエストの結果(具体的には、新しく作成された取引先のid
)を、この取引先責任者のAccountId
として指定しています。これにより、2つのレコードが正しく関連付けられます。
成功時のレスポンス例
{ "compositeResponse" : [{ "body" : { "id" : "001xx000003DHPF", "success" : true, "errors" : [ ] }, "httpHeaders" : { "Location" : "/services/data/v58.0/sobjects/Account/001xx000003DHPF" }, "httpStatusCode" : 201, "referenceId" : "refAccount" },{ "body" : { "id" : "003xx000002bBrL", "success" : true, "errors" : [ ] }, "httpHeaders" : { "Location" : "/services/data/v58.0/sobjects/Contact/003xx000002bBrL" }, "httpStatusCode" : 201, "referenceId" : "refContact" }] }
レスポンスを見ると、compositeResponse
配列の中に2つの要素があり、それぞれがrefAccount
とrefContact
に対応していることがわかります。両方ともhttpStatusCode
が201
(Created) であり、処理が成功したことを示しています。
注意事項
Composite APIは非常に便利ですが、効果的に使用するためにはいくつかの重要な注意点を理解しておく必要があります。
APIガバナ制限
最も重要な注意点です。Composite APIは、HTTPリクエストの数は1回に削減しますが、SalesforceのAPIコール数のガバナ制限の消費は削減しません。各サブリクエストは、個別のAPIコールとしてカウントされます。上記の例では、1回のHTTPリクエストで2つのサブリクエストを送信しているため、組織の24時間あたりのAPIコール上限から「2」を消費します。この点を誤解すると、意図せずAPI制限に達してしまう可能性があるため、慎重な設計が必要です。
サブリクエストの上限
1つのComposite APIリクエストに含めることができるサブリクエストの数には上限があります。標準の /composite
エンドポイントでは、最大25個のサブリクエストを含めることができます。より多くのリクエストをバッチ処理したい場合は、最大200個のサブリクエストをサポートする /composite/batch
エンドポイントの利用を検討してください。ただし、数千、数万件の大量データを扱う場合は、Bulk APIの方が適しています。
エラーハンドリング
allOrNone
がfalse
の場合、あるいはAPIコール全体が何らかの理由で失敗した場合に備え、堅牢なエラーハンドリングが不可欠です。クライアント側のアプリケーションは、レスポンスのcompositeResponse
配列をループ処理し、各要素のhttpStatusCode
を確認する必要があります。ステータスコードが200番台でない場合は、body
に含まれるエラーメッセージを解析し、リトライ処理やエラーログの記録など、適切な対応を行う必要があります。
権限
Composite APIを実行する連携ユーザーは、リクエストに含まれるすべてのサブリクエストを実行するために必要な権限(オブジェクトレベル、項目レベルのセキュリティ、共有ルールなど)を持っている必要があります。いずれか一つの操作に対する権限が不足している場合、そのサブリクエストは失敗します。
まとめとベストプラクティス
Salesforce Composite APIは、統合エンジニアにとって、効率的で信頼性の高い連携ソリューションを構築するための不可欠なツールです。複数のAPIコールを単一のリクエストにまとめることで、ネットワーク遅延を大幅に削減し、アトミックなトランザクションを保証することで、データの整合性を高めることができます。
統合エンジニアとして、Composite APIを最大限に活用するためのベストプラクティスを以下にまとめます。
- 論理的な作業単位でグループ化する: 互いに関連性の高い一連の操作(例:親レコードと子レコードの作成)を1つのCompositeリクエストにまとめましょう。無関係な操作を無理にまとめることは避けるべきです。
- トランザクションの必要性に応じて `allOrNone` を選択する: データの整合性が最優先されるシナリオでは、必ず `allOrNone=true` を使用します。部分的な成功が許容される稀なケースでのみ `false` の使用を検討し、その場合は複雑なエラーハンドリングを実装する覚悟が必要です。
- API消費量を常に意識する: Composite APIがAPIガバナ制限の「節約」にはならないことを肝に銘じ、設計段階でAPIコール数を正確に見積もりましょう。
- 依存関係はシンプルに保つ: Reference IDによる依存関係は非常に強力ですが、複雑にしすぎるとデバッグが困難になります。可能な限り、前方参照のみのシンプルなフローを維持しましょう。
- 適切なAPIツールを選択する: Composite APIは、数件から数十件のレコードを扱う場合に最適です。数百件以上のデータを扱う場合は
/composite/batch
や Bulk API 2.0、より複雑なオブジェクトグラフを扱う場合は Composite Graph API など、シナリオに応じて最適なAPIを選択することが重要です。
これらの原則に従うことで、Salesforce Composite APIを駆使し、パフォーマンス、信頼性、保守性に優れた連携システムを構築することができるでしょう。
コメント
コメントを投稿