背景と適用シナリオ
Salesforce 開発者の皆様、こんにちは。日々の業務で外部システムとの連携は避けて通れないタスクの一つかと思います。従来、これを実現する主な方法は Apex Callouts でした。HTTPリクエストの作成、認証ヘッダーの管理、JSON のシリアライズ・デシリアライズ、そして何より、これらすべてをカバーするテストクラスの作成など、多くの定型的なコーディングが必要でした。
しかし、Salesforce Platform は進化を続けています。その中でも、特に API 連携のあり方を大きく変える可能性を秘めているのが External Services (外部サービス) です。
External Services は、OpenAPI Specification (OpenAPI 仕様) という標準的な API 定義ファイルをもとに、外部の REST API への接続を宣言的に(コードを書かずに)設定できる機能です。この機能の素晴らしい点は、一度設定すれば、その API 操作が Flow や Einstein ボットなどのノーコード・ローコードツールで利用可能なInvocable Action (呼び出し可能なアクション)として自動的に生成されることです。
私たち開発者にとって、これは単に「コードが減る」以上の意味を持ちます。
- 開発の高速化: シンプルなデータ取得や更新であれば、Apex コードを一行も書かずに数分で連携を実装できます。
- 保守性の向上: 認証情報は Named Credential (指定ログイン情報) で一元管理されるため、エンドポイントや認証情報の変更に強く、コードの修正が不要になります。
- 管理者との協業: 私たちが External Services を設定してあげることで、Salesforce 管理者は Flow を使って自由にビジネスプロセスを自動化できます。開発者はより複雑なロジックに集中できるのです。
具体的な適用シナリオとしては、以下のようなケースが考えられます。
- 住所検証サービス: 取引先責任者の住所が入力された際に、外部の API を呼び出して正規化・検証する。
- リアルタイム株価情報: 商談画面で、関連する企業の最新の株価情報を外部 API から取得して表示する。
- 翻訳サービス: ケースの件名や説明を、ボタン一つで指定した言語に翻訳する。
- 社内マイクロサービス連携: Salesforce 外に構築された自社のマイクロサービス(在庫確認、与信チェックなど)を呼び出す。
原理の説明
External Services が魔法のように機能する裏には、3つの重要なコンポーネントが連携しています。開発者としてこれらの仕組みを理解することは、トラブルシューティングや最適な設計を行う上で非常に重要です。
1. OpenAPI 仕様 (OpenAPI Specification)
すべての始まりは OpenAPI 仕様ファイルです。これは以前 Swagger と呼ばれていたもので、REST API の「設計図」にあたります。このファイルには、API のエンドポイント、利用可能な HTTP メソッド (GET, POST, PUT, DELETEなど)、リクエストに必要なパラメータ、そしてレスポンスのデータ構造などが、JSON または YAML 形式で記述されています。Salesforce はこのファイルを読み込み、API の全体像を理解します。そして、この定義に基づいて Apex クラスや Invocable Action を内部的に自動生成するのです。
2. 指定ログイン情報 (Named Credential)
API 連携において認証情報の管理は最も注意を払うべき点です。Named Credential (指定ログイン情報) は、この問題を解決するための Salesforce の標準機能です。External Services は Named Credential と密接に連携します。API のエンドポイント URL や、API キー、OAuth 2.0 の認証フローといった複雑な認証情報を安全に格納し、管理することができます。開発者としての最大のメリットは、コードや Flow から認証情報が完全に分離されることです。例えば、サンドボックス環境と本番環境で API エンドポイントやキーが違っていても、それぞれの環境で Named Credential の設定を変えるだけで、コードや Flow の修正は一切不要になります。
3. 呼び出し可能なアクション (Invocable Action)
OpenAPI 仕様を登録し、Named Credential を関連付けると、Salesforce は OpenAPI 仕様で定義された各 API 操作(オペレーション)に対応する Invocable Action (呼び出し可能なアクション) を生成します。例えば、`getAccount` と `addAccount` という2つの操作が定義されていれば、同名のアクションが作られます。これらのアクションは、以下のような様々な場所から呼び出すことができます。
- Flow Builder: 「アクション」要素を配置し、生成されたアクションを選択して、入力と出力をマッピングするだけで API を呼び出せます。
- Apex: 自動生成された Apex クラスを利用して、数行のコードでタイプセーフな API 呼び出しが可能です。これにより、JSON の手動パースなどの手間が省けます。
- Einstein ボット: 対話フローの中で外部 API を呼び出し、動的な応答を生成できます。
この仕組みにより、一度のセットアップで、宣言的なツールとプログラム的なアプローチの両方から、統一されたインターフェースで外部 API を利用できるのです。
サンプルコード
ここでは、シンプルな銀行口座サービスを想定した External Service の設定と、それを Apex から呼び出す方法を具体的に見ていきましょう。この例は Salesforce の公式ドキュメントに基づいています。
OpenAPI 2.0 仕様の例 (銀行サービス)
まず、以下のような OpenAPI 2.0 の JSON スキーマを準備します。このスキーマは、口座の追加 (`addAccount`) と、複数の口座の照会 (`getAccounts`) という2つの操作を定義しています。
{ "swagger": "2.0", "info": { "title": "Bank Service", "description": "API for creating and retrieving bank accounts", "version": "1.0.0" }, "host": "my-bank-service.com", "basePath": "/accounts", "schemes": [ "https" ], "paths": { "/": { "get": { "summary": "Get Accounts", "description": "Fetches a list of bank accounts.", "operationId": "getAccounts", "produces": [ "application/json" ], "responses": { "200": { "description": "OK", "schema": { "type": "array", "items": { "$ref": "#/definitions/Account" } } } } }, "post": { "summary": "Add Account", "description": "Creates a new bank account.", "operationId": "addAccount", "consumes": [ "application/json" ], "produces": [ "application/json" ], "parameters": [ { "in": "body", "name": "body", "required": true, "schema": { "$ref": "#/definitions/NewAccount" } } ], "responses": { "201": { "description": "Created" } } } } }, "definitions": { "Account": { "type": "object", "properties": { "id": { "type": "string" }, "name": { "type": "string" }, "balance": { "type": "number" } } }, "NewAccount": { "type": "object", "properties": { "name": { "type": "string" } } } } }
Apex からのアクション呼び出し
上記のスキーマを `BankService` という名前で External Service として登録したとします。Salesforce は内部的に `ExternalService.BankService` という名前空間を持つ Apex クラスを生成します。これを利用して、Apex から `addAccount` 操作を呼び出すコードは以下のようになります。
// Salesforce 開発者として、生成された Apex クラスを利用して外部 API を呼び出す public class BankServiceCaller { public static void createNewAccount(String accountName) { try { // 1. リクエストボディのインスタンスを作成 // スキーマの "NewAccount" definition に対応する Apex 内部クラスが生成される ExternalService.BankService.NewAccount newAccountRequest = new ExternalService.BankService.NewAccount(); newAccountRequest.name = accountName; // 2. リクエスト全体のラッパーオブジェクトを作成 // addAccount 操作(operationId)に対応するリクエストクラス ExternalService.BankService.addAccount_Request requestWrapper = new ExternalService.BankService.addAccount_Request(); requestWrapper.body = newAccountRequest; // 3. 外部サービスを呼び出す // "BankService" はサービス名、"addAccount" は operationId に対応 // 戻り値はレスポンスオブジェクト ExternalService.BankService.addAccount_Response response = ExternalService.BankService.addAccount(requestWrapper); // 4. レスポンスを処理する // HTTP ステータスコードが 201 (Created) であることを確認 if (response.Code == 201) { System.debug('口座が正常に作成されました。'); } else { System.debug('口座の作成に失敗しました。ステータスコード: ' + response.Code); System.debug('エラーメッセージ: ' + response.Message); } } catch (ExternalService.ExternalServiceException e) { // 5. 例外処理 // ネットワークエラーや認証エラーなどをキャッチ System.debug('External Service の呼び出しで例外が発生しました。'); System.debug('ステータスコード: ' + e.getStatusCode()); System.debug('エラーメッセージ: ' + e.getMessage()); } } } // 実行例: Execute Anonymous Window で実行 // BankServiceCaller.createNewAccount('My New Savings Account');
ご覧のように、HTTP のセットアップや JSON のパースは一切不要です。生成されたクラスのプロパティに値を設定し、メソッドを呼び出すだけで、タイプセーフな API 連携が実現できています。これは開発効率を劇的に向上させます。
注意事項
External Services は非常に強力ですが、利用する上でいくつか注意すべき点があります。
権限とセキュリティ (Permissions and Security)
- 設定時の権限: External Service や Named Credential を作成・変更するには、「アプリケーションのカスタマイズ」権限が必要です。
- 実行時の権限: Named Credential にはプロファイルや権限セット単位でのアクセス制御が可能です。Flow や Apex を実行するユーザーが、対象の Named Credential へのアクセス権を持っていることを確認してください。
API とガバナ制限 (API and Governor Limits)
External Services を利用したコールアウトも、Salesforce の標準的なガバナ制限に従います。
- コールアウトの合計数: 1トランザクションあたりの同期 Apex でのコールアウト上限は 100 回です。External Services の呼び出しもこの数に含まれます。
- タイムアウト: コールアウトのタイムアウトは最大 120 秒です。
- スキーマの制限: 登録できるスキーマのサイズや、定義できるオブジェクト、プロパティの数には上限があります。詳細は Salesforce の公式ドキュメントで最新の情報を確認してください。
- 登録数の上限: 1組織あたりの External Service 登録数にも上限があります。
エラーハンドリング (Error Handling)
外部連携にエラーはつきものです。堅牢な実装のためには、エラーハンドリングが不可欠です。
- Flow の場合: 「アクション」要素に表示される「フォルトパス」を必ず設定してください。API から 4xx や 5xx 系のエラーが返された場合や、タイムアウトした場合に、このパスが実行されます。ここでエラー内容をログに記録したり、ユーザーに通知したりする処理を実装します。
- Apex の場合: 上記のサンプルコードのように、必ず
try-catch
ブロックで呼び出しを囲み、ExternalService.ExternalServiceException
をキャッチしてください。この例外オブジェクトから HTTP ステータスコードやレスポンスボディを取得し、詳細なエラー分析やリトライ処理を実装することが可能です。
スキーマのサポートと制約 (Schema Support and Constraints)
External Services は OpenAPI 2.0 および 3.0 をサポートしていますが、仕様のすべてに対応しているわけではありません。特に、以下のような高度な機能はサポートされていないか、制限があります。
- 複合スキーマ: `oneOf`, `anyOf`, `allOf`, `not` といったキーワードは完全にはサポートされていません。
- 再帰的なスキーマ定義: 自分自身を参照するようなスキーマ定義はサポートされていません。
- Content-Type: 主に `application/json` がサポートされますが、POST 操作では `application/x-www-form-urlencoded` もサポートされています。
連携したい API の OpenAPI 仕様が複雑な場合は、まず External Services でサポートされているかを確認し、必要であれば API 提供者と協力して、よりシンプルなスキーマに修正してもらうか、従来の Apex Callout を選択する必要があります。
まとめとベストプラクティス
External Services は、Salesforce における API 連携のパラダイムを大きく変える強力な機能です。開発者としてこのツールを使いこなすことで、開発速度の向上、保守性の高いアーキテクチャの実現、そしてビジネスサイドとの円滑な協業が可能になります。
最後に、External Services を活用するためのベストプラクティスをまとめます。
- 常に指定ログイン情報を使用する (Always Use Named Credentials)
セキュリティと保守性の観点から、認証情報は必ず Named Credential で管理してください。これにより、環境間の移行や認証情報の更新が容易になります。 - OpenAPI 仕様をシンプルに保つ (Keep OpenAPI Specs Simple)
連携に必要な操作のみを含む、最小限の OpenAPI 仕様を作成・利用することを推奨します。巨大な仕様ファイルをそのまま登録すると、不要なアクションが大量に生成され、管理が煩雑になります。 - 堅牢なエラー処理を実装する (Implement Robust Error Handling)
API 呼び出しが常に成功するとは限りません。Flow のフォルトパスや Apex の try-catch を活用し、予期せぬエラーが発生した場合でも、ビジネスプロセスが停止したり、データが不整合になったりしないように設計してください。 - 適切なツールを選択する (Choose the Right Tool for the Job)
External Services は万能ではありません。標準的な REST/JSON API とのシンプルな連携には最適ですが、SOAP API、複雑な認証ロジック、あるいはコールアウト前後に大量のデータ加工が必要な場合は、引き続き柔軟性の高い Apex Callout を利用するのが賢明な判断です。
External Services を武器の一つとして持っておくことで、私たちの開発者としての価値はさらに高まるでしょう。ぜひ次のプロジェクトで活用を検討してみてください。
コメント
コメントを投稿