外部サービスの非同期コールバックのしくみ
外部サービスの非同期操作は、コールバック操作と共に OpenAPI 3.x 準拠仕様で説明されています。非同期操作は、より長い応答時間を設定できる特殊な呼び出し可能アクション種別としてシステムによって登録されます。一方、外部サービスの同期操作は 120 秒でタイムアウトとなります。非同期操作では、Apex を使用して、コールバックおよび遅延した非同期応答のタイムアウトを定義します。
必要なエディション
| 使用可能なインターフェース: Lightning Experience |
| 使用可能なエディション: Enterprise Edition、Performance Edition、Unlimited Edition、および Developer Edition |
コールバック操作を使用した API 仕様の例
この API 仕様の例では、架空の企業である「Acme Mortgages」の住宅ローン申込プロセス内のコールバック操作が使用されています。コールバック関連の定義は太字で表示されます。この例については、このセクションの他のトピックで説明します。
{
"openapi": "3.0.0",
"servers": [{
"url": "/"
}],
"info": {
"version": "1.0",
"title": "Acme Mortgages",
"description": "Acme Mortgages"
},
"paths": {
"/applications": {
"post": {
"operationId": "SubmitApplication",
"description": "Submit a new mortgage application",
"parameters": [{
"name": "callbackUrlForErrorCases",
"in": "query",
"schema": {
"type": "string"
}
}],
"requestBody": {
"content": {
"application/json": {
"schema": {
"type": "object",
"properties": {
"applicant": {
"$ref": "#/components/schemas/Contact"
},
"callbackUrlForOutcomes": {
"type": "object",
"properties": {
"approved": {
"type": "string"
},
"rejected": {
"type": "string"
}
}
}
}
}
}
}
},
"responses": {
"201": {
"description": "Mortgage loan application submission initial response",
"content": {
"application/json": {
"schema": {
"type": "object",
"properties": {
"applicationNumber": {
"type": "string"
}
}
}
}
}
}
},
"callbacks": {
"applicationOutcomeApproved": {
"$ref": "#/components/callbacks/ApplicationApproved"
},
"applicationOutcomeRejected": {
"$ref": "#/components/callbacks/ApplicationRejected"
},
"applicationError": {
"{$request.query.callbackUrlForErrorCases}": {
"post": {
"parameters": [{
"in": "header",
"name": "applicationNumber",
"schema": {
"type": "string"
}
}],
"requestBody": {
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/MortgageApplicationError"
}
}
}
},
"responses": {
"200": {
"description": "Mortgage application callback error accepted"
}
}
}
}
}
}
}
}
},
"components": {
"schemas": {
"MortgageApplication": {
"required": [
"applicationNumber",
"status"
],
"properties": {
"applicationNumber": {
"type": "string"
},
"status": {
"description": "One of pending, approved, rejected",
"type": "string"
},
"approvedAmount": {
"type": "number"
}
}
},
"Contact": {
"type": "object",
"required": [
"name"
],
"properties": {
"name": {
"type": "string"
},
"address": {
"type": "string"
}
}
},
"MortgageApplicationError": {
"properties": {
"errorMessage": {
"type": "string"
},
"applicationNumber": {
"type": "string"
}
}
}
},
"callbacks": {
"ApplicationApproved": {
"{$request.body#/callbackUrlForOutcomes/approved}": {
"post": {
"description": "Application has been approved.",
"operationId": "approvedCallback",
"requestBody": {
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/MortgageApplication"
}
}
}
},
"responses": {
"200": {
"description": "Approved application callback result has been retrieved successfully."
}
}
}
}
},
"ApplicationRejected": {
"{$request.body#/callbackUrlForOutcomes/rejected}": {
"post": {
"description": "Application is rejected",
"requestBody": {
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/MortgageApplicationError"
}
}
}
},
"responses": {
"200": {
"description": "Rejected application callback result has been retrieved successfully."
}
}
}
}
}
}
}
}
非同期操作を使用した Apex インターフェースの例
登録されると、AcmeMortgages 外部サービスが外部サービスによって Apex に自動的に表示されます。AcmeMortgages の Apex インターフェイスは、次のように [設定] の [Apex クラス] ページに表示されます。非同期操作を定義する追加コンテンツは太字で表示されます。ここでは、呼び出し可能なアクションと同じスキーマオブジェクトデータ型を表す動的 Apex オブジェクトは表示されていません。
各コールバックは、その親非同期操作によって所有されます。一意の参照のみのコールバック URL は、Salesforce によって (最初のコールアウト時に) 決定されます。
global class AcmeMortgages {
// Acme Mortgages SubmitApplication asynchronous operation
global SubmitApplication_Response SubmitApplication(
SubmitApplication_Request input,
SubmitApplication_Callback callback,
DateTime callbackTimeout
) {...}
global class SubmitApplication_Request {
global AcmeMortgages_SubmitApplication_IN_body body {get; set;}
// [REQUEST] Callback URL for asynchronous operation: callbackUrlForErrorCases
global String callbackUrlForErrorCases {get;}
}
// Synchronous response - here getting the application docket number
global class SubmitApplication_Response {
global Integer responseCode {get; set;}
global AcmeMortgages_SubmitApplication_OUT_201 Code201 {get; set;}
// Get invocation ID for this asynchronous response to query callback status
global String invocationId {get;}
}
global class SubmitApplication_ResponseException {
global Integer responseCode {get; set;}
global String defaultResponse {get; set;}
}
// Asynchronous response callback handler for SubmitApplication.
// Each method corresponds to the schema's declared callback key.
// Default implementations throws an exception alerting that a non-implemented callback was called.
global virtual class SubmitApplication_Callback {
global virtual void applicationOutcomeApproved(
List<SubmitApplication_applicationOutcomeApproved_Callback> callbacks) {
throw new SubmitApplication_ResponseException(404,
'Callback not handled: applicationOutcomeApproved');
}
global virtual void applicationOutcomeRejected(List<SubmitApplication_applicationOutcomeRejected_Callback> callbacks) {...}
global virtual void applicationError(List<SubmitApplication_applicationError_Callback> callbacks) {...}
}
// Asynchronous callback response payloads for callback applicationOutcomeApproved
global class SubmitApplication_applicationOutcomeApproved_Callback {
global SubmitApplication_Request request {get; set;}
global DateTime submitTime {get; set;}
global DateTime callbackTimeout {get; set;}
global CallbackStatus callbackStatus {get; set;}
global SubmitApplication_applicationOutcomeApproved_CallbackResponse response {get; set;}
}
global class SubmitApplication_applicationOutcomeApproved_CallbackResponse {
global AcmeMortgages_MortgageApplication body {get; set;}
}
global class SubmitApplication_applicationOutcomeRejected_Callback {...}
global class SubmitApplication_applicationOutcomeRejected_CallbackResponse {...}
global class SubmitApplication_applicationError_Callback {...}
global class SubmitApplication_applicationError_CallbackResponse {...}
}
コールバックデータフローの例
この例では、Salesforce Apex 開発者は外部サービスを使用して、銀行の住宅ローン申込 API 仕様を登録します。仕様には、申込の送信から承認までに最大 1 日の遅延が予想されるため、コールバック操作が含まれています。
Apex 開発者は、コールバックハンドラーを使用して Apex クライアントを記述します。Apex クライアントによって、Salesforce が外部システムから遅延応答を受け取った後に、Salesforce がその結果の名前リストやその他の住宅ローン申込情報を使用して取引先責任者を自動的に作成することが指定されます。
次のシーケンスダイアグラムは、開発者の Apex コード (ダイアグラム内の「Apex Client / Handler (Apex クライアント/ハンドラー)」)、Salesforce、銀行の住宅ローン申込 API エンドポイント (ダイアグラム内の「External Webservice (外部 Web サービス)」) 間の機能的なデータフローを示しています。
外部 Web サービスからは 2 つの応答があります。最初の応答は同期であり、典型的な最初の ACK 応答です。2 つ目の応答は、リクエストボディに結果のペイロードを含む非同期の遅延応答 (技術的には要求) です。
まず、Apex 開発者は Apex クライアントを使用して銀行サーバー (外部サービス) に HTTP 要求 (コールアウト) を送信します。
外部 Web サービスは、要求を受信したことを確認する HTTP 応答をすぐに返します。この最初の受信確認は 120 秒後にタイムアウトします。Salesforce 開発者は、バックグラウンド操作ページまたは Apex デバッグログを使用して、要求の状況を監視します。
銀行は内部プロセスを開始し、住宅ローン申込を取り込み、承認または却下した後、最終的に最終的な結果を準備します (ダイアグラム内の「Async Delay (非同期遅延)」)。
1 日以内に、銀行は完了した結果を HTTP 要求として Apex 開発者に送信します。住宅ローン申込の結果データ (承認済み金額や状況など) は、リクエストボディ内に含まれます。Salesforce は結果を受信し、Apex コールバックハンドラー実装に従って処理します。
Salesforce は HTTP 応答確認を外部 Web サービスに返します。Salesforce はデータを正常に処理すると (このケースでは、取引先責任者の作成)、外部 Web サービスに 200 状況コードと成功メッセージを含む応答を送信します。
Salesforce でエラーが発生した場合は、汎用的なエラーメッセージと共に 404、408、または 500 の状況コードを外部 Web サービスに送信します。Apex 開発者は、バックグラウンド操作ページまたは Apex デバッグログを使用して、エラーメッセージの詳細を表示できます。
