building-omnistudio-callable-apex について
System.Callable を用いた Salesforce Industries の呼び出し可能な Apex を作成、レビュー、移行するスキルです。OmniStudio の拡張ポイントを統合する開発者向けに、明示的なアクション契約、安全なデータアクセス、一貫した応答、テストを重視します。
主な機能
- 01System.Callable 実装の生成
- 02呼び出し可能なコードのリスクレビュー
- 03旧 Vlocity インターフェースの移行
- 04アクションと応答契約の定義
- 05CRUD/FLS と共有設定の適用
- 06120 点の基準による検証
活用シーン
- 01OmniStudio の呼び出しアクション実装
- 02VlocityOpenInterface クラスの更新
- 03入力契約と一括処理のテスト
インストール
コマンドをコピーしてターミナルで実行します。
npx skills add https:/ / github.com/ forcedotcom/ sf-skills --skill building-omnistudio-callable-apexインストール後、Claude Code で/building-omnistudio-callable-apexを入力して読み込まれたか確認します。
同梱ファイル
SKILL.md と一緒にインストールされる参考資料やスクリプト。
CREDITS.mdREADME.mdassets/pattern_callable_openinterface.clspattern_callable_vanilla.clspattern_migration.clspattern_openinterface.clspattern_test_class.clsexamples/Test_QuoteByProductCallable/Industries_QuoteByProductCallable.clsIndustries_QuoteByProductCallableTest.clsIndustriesCallableException.clsTRANSCRIPT.mdexamples/Test_VlocityOpenInterface2Conversion/IndustriesCallableException.clsMyCustomCallable.clsMyCustomCallableTest.clsMyCustomRemoteClass.clsTRANSCRIPT.mdexamples/Test_VlocityOpenInterfaceConversion/IndustriesCallableException.clsMyCustomCallable.clsMyCustomCallableTest.clsMyCustomVlocityOpenInterface2.clsTRANSCRIPT.md詳細
building-omnistudio-callable-apex:Salesforce Industries Common Core の Callable Apex
Salesforce Industries Common Core の Callable Apex 実装に特化しています。OmniStudio および Industries の拡張ポイントと適切に統合できる、安全で決定性があり、設定可能な Apex を作成します。
対象範囲
- 対象:Industries の拡張ポイント向け
System.Callableクラスの作成、正確性とリスクに関する Callable 実装のレビュー、VlocityOpenInterface/VlocityOpenInterface2からSystem.Callableへの移行、120 点満点でのスコアリングと検証 - 対象外:Callable インターフェースを実装しない汎用 Apex クラス(
generating-apexを使用)、Integration Procedure の構築(building-omnistudio-integration-procedureを使用)、OmniScript の作成(building-omnistudio-omniscriptを使用)、Apex クラスのデプロイ(deploying-metadataを使用)
主な責務
- Callable の生成:安全なアクションディスパッチを備えた
System.Callableクラスを構築する - Callable のレビュー:既存の Callable 実装の正確性とリスクを監査する
- 検証とスコアリング:120 点満点の評価基準に照らして評価する
- Industries への適合:OmniStudio/Industries の拡張ポイントとの互換性を確保する
ワークフロー(4 フェーズパターン)
フェーズ 1:要件の収集
以下を確認します。
- エントリーポイント(OmniScript、Integration Procedure、DataRaptor、その他の Industries フック)
- アクション名(
callに渡される文字列) - 入力/出力の契約(必須キー、型、レスポンスの形式)
- データアクセスの要件(オブジェクト/項目、CRUD/FLS(作成/読み取り/更新/削除と項目レベルセキュリティ)のルール)
- 副作用(DML、コールアウト、非同期処理の要件)
続いて、以下を行います。
- 既存の Callable クラスを検索します:
Glob: **/*Callable*.cls - Industries の拡張機能で使用されている共通ユーティリティまたは基底クラスを特定します
- タスクリストを作成します
フェーズ 2:設計と契約の定義
Callable の契約を定義します。
- アクション一覧(明示的で、バージョン管理された文字列)
- 入力スキーマ(必須キーと型)
- 出力スキーマ(一貫したレスポンスエンベロープ)
推奨するレスポンスエンベロープ:
{
"success": true|false,
"data": {...},
"errors": [ { "code": "...", "message": "..." } ]
}
アクションディスパッチのルール:
switch on actionを使用する- デフォルトケースでは型付き例外をスローする
- 動的なメソッド呼び出しやリフレクションは使用しない
VlocityOpenInterface / VlocityOpenInterface2 の契約マッピング:
レガシーの Open Interface 拡張機能向けに設計する場合(または Callable と Open Interface の両方をサポートする場合)、シグネチャを次のようにマッピングします。
invokeMethod(String methodName, Map<String, Object> inputMap, Map<String, Object> outputMap, Map<String, Object> options)
| パラメーター | 役割 | Callable での対応 |
|---|---|---|
methodName | アクションセレクター(action と同じ意味) | call(action, args) の action |
inputMap | 主な入力データ(必須キー、型) | args.get('inputMap') |
outputMap | 結果を書き込む変更可能なマップ(参照渡しで出力) | 戻り値。Callable は代わりにエンベロープを返す |
options | 追加のコンテキスト(親 DataRaptor/OmniScript のコンテキスト、呼び出しメタデータ) | args.get('options') |
Open Interface の契約に関する設計ルール:
inputMapとoptionsを、組み合わせた入力スキーマとして扱う- アクションごとに
outputMapに書き込む必要があるキー(成功時とエラー時)を定義する methodNameの文字列を維持し、Callable のaction文字列と一致させる- アクションごとに、
optionsが必須、任意、または未使用のいずれであるかを文書化する
フェーズ 3:実装パターン
Vanilla System.Callable(フラットな引数、Open Interface との結合なし):
生成前に assets/pattern_callable_vanilla.cls をお読みください。呼び出し元がフラットな引数を渡し、VlocityOpenInterface との統合が不要な場合に使用します。
Callable のひな形(VlocityOpenInterface と同じ入力):
生成前に assets/pattern_callable_openinterface.cls をお読みください。Open Interface と統合する場合、または呼び出し元がその構造を渡す場合は、args 内の inputMap と options のキーを使用します。
入力形式:呼び出し元は args を { 'inputMap' => Map<String, Object>, 'options' => Map<String, Object> } として渡します。フラットな引数を渡す呼び出し元との後方互換性を保つため、args に 'inputMap' がない場合は、args 自体を inputMap として扱い、options には空のマップを使用します。
実装ルール:
call()は薄く保ち、プライベートメソッドまたはサービスクラスに処理を委譲します- 入力の型を早い段階で検証し、変換します(null セーフにします)
- CRUD/FLS(作成/読み取り/更新/削除と項目レベルセキュリティ)および共有設定(
with sharing、Security.stripInaccessible())を適用します argsにレコードコレクションが含まれる場合は、一括処理に対応させます- 適切な場合は、SOQL に
WITH USER_MODEを使用します - 名前空間の処理:
System.Callableは標準インターフェースであり、名前空間プレフィックスは不要です。omnistudio.VlocityOpenInterface2は管理パッケージの名前空間omnistudioを使用するため、必ず名前空間を指定します。Callable クラスを名前空間付きの管理パッケージにデプロイする場合は、ユーザーに名前空間プレフィックスを確認し、カスタムクラス名に適用します(例:myns__Industries_XxxCallable)
VlocityOpenInterface/VlocityOpenInterface2 の実装:
omnistudio.VlocityOpenInterface または omnistudio.VlocityOpenInterface2 を実装する場合は、次のシグネチャを使用します。
global Boolean invokeMethod(String methodName, Map<String, Object> inputMap,
Map<String, Object> outputMap, Map<String, Object> options)
生成前に assets/pattern_openinterface.cls をお読みください。switch on によるディスパッチと outputMap の契約を含む、VlocityOpenInterface2 の完全なひな形です。
Open Interface の実装ルール:
putAll()または個別のput()呼び出しを使用して、結果をoutputMapに書き込みます。invokeMethodからエンベロープを返さないでください- 成功時は
true、サポートされていないアクションまたは失敗時はfalseを返します - Callable と同じ内部プライベートメソッドを使用し、同じ
inputMapとoptionsパラメーターを渡します。異なるのはエントリーポイントのみです - 一貫性を保つため、同じエンベロープ形式(
success、data、errors)でoutputMapを設定します
Callable と Open Interface は同じ入力(inputMap、options)を受け取り、共通ロジックについては同一のプライベートメソッドシグネチャに処理を委譲します。
フェーズ 4:テストと検証
最低限必要なテスト:
- 正常系:サポートされているアクションが正常に実行される
- 異常系:サポートされていないアクションで想定された例外がスローされる
- 契約:入力が不足または無効な場合に、エラーエンベロープが返される
- 一括処理:リスト入力を処理し、制限に達しない
テスト生成前に assets/pattern_test_class.cls をお読みください。正常系、異常系、契約、一括処理、null の引数のケースを含む完全なテストクラスのひな形です。
VlocityOpenInterface から System.Callable への移行
Industries の拡張機能を最新化する際は、VlocityOpenInterface または
VlocityOpenInterface2 の実装を System.Callable に移行し、
アクションの契約を維持します。
ガイダンス:
methodNameのアクション名を、call()内のaction文字列として維持しますinputMapとoptionsをargs内のキーとして渡します:{ 'inputMap' => inputMap, 'options' => options }outMapを変更する代わりに、一貫したレスポンスエンベロープを返しますcall()は薄く保ち、(inputMap, options)シグネチャを持つ同じ内部メソッドに処理を委譲します- 各アクションとサポートされていないアクションのテストを追加します
移行を始める前に assets/pattern_migration.cls をお読みください。VlocityOpenInterface2 から System.Callable への移行例を、移行前後の注釈付きで示しています。
ベストプラクティス(120点満点の評価)
| カテゴリ | 点数 | 主なルール |
|---|---|---|
| コントラクトとディスパッチ | 20 | 明示的なアクションリスト、switch on、バージョン付きアクション文字列 |
| 入力検証 | 20 | 必須キーを検証する、安全に型変換する、null ガード |
| セキュリティ | 20 | with sharing、CRUD/FLS チェック、Security.stripInaccessible() |
| エラー処理 | 15 | 型付き例外、一貫したエラーエンベロープ、空の catch を使わない |
| 一括処理と制限 | 20 | ループ内で SOQL/DML を実行しない、リスト入力をサポートする |
| テスト | 15 | 正常系/異常系/コントラクト/一括処理のテスト |
| ドキュメント | 10 | クラスとアクションメソッドに ApexDoc(/** ... */ のブロックコメント — Salesforce Apex ドキュメント標準)を記述する |
しきい値:✅ 90以上(準備完了) | ⚠️ 70~89(レビュー) | ❌ 70未満(ブロック)
⛔ ガードレール(必須)
以下のいずれかを導入する場合は作業を止め、ユーザーに確認してください。
- ユーザー入力に基づく動的なメソッド実行(リフレクションは禁止)
- ループ内での SOQL/DML
- 呼び出し可能なクラスでの
without sharing - サイレント失敗(空の catch、例外の握りつぶし)
- アクション間で一貫性のないレスポンス形式
注意点
| 問題 | 解決方法 |
|---|---|
呼び出し元はフラットな引数を渡すが、コードは inputMap キーを想定している | 防御的に処理する:args に 'inputMap' キーがない場合、args 自体を入力マップとして扱う |
call() が args に null を受け取る | キーにアクセスする前に必ず args が null か確認し、null の場合は空のマップに初期化する |
テストクラスで (Map<String, Object>) svc.call(...) を使っているが、call の戻り値の型が正しくない | すべてのアクションで同じエンベロープ型(Map<String, Object>)を返すようにする — 戻り値の型が混在すると呼び出し元で問題が発生する |
VlocityOpenInterface2 の移行により、outputMap を参照渡しで読み取る呼び出し元が動作しなくなる | Callable への移行後、呼び出し元は outputMap ではなく戻り値を読み取る必要がある — すべての呼び出し元を更新する |
プロジェクトに IndustriesCallableException クラスがない | このカスタム例外は呼び出し可能クラスと一緒にデプロイする必要がある — すべてのデプロイパッケージに含める |
| 組織でレガシー Open Interface と新しい Callable の両方が同じアクションに接続されている | 同時に有効にするエントリーポイントは1つだけにする。Callable が動作することを確認した後、古いインターフェースを無効にする |
よくあるアンチパターン
call()にビジネスロジックを含め、委譲していない- アクション名にバージョンがなく、ドキュメントもない
- 入力マップにキーがあることを確認せずに使用している
- 戻り値の型が混在している(Map の場合も String の場合もある)
- 未サポートのアクションに対するテストがない
スキル間の連携
| スキル | 使用する場面 | 例 |
|---|---|---|
| generating-apex | Callable の実装以外の一般的な Apex 作業 | 「Account のトリガーを作成する」 |
| generating-custom-object / generating-custom-field | コーディング前にオブジェクト/フィールドが利用可能か確認する | 「Product2 のフィールドを記述する」 |
| deploying-metadata | Callable クラスを検証/デプロイする | 「サンドボックスにデプロイする」 |
参照スキル
以下にある Apex の基本標準、テストパターン、ガードレールを使用してください。
同梱の例
- examples/Test_QuoteByProductCallable/ —
WITH USER_MODEを使った読み取り専用クエリの例 - examples/Test_VlocityOpenInterfaceConversion/ — レガシーの
VlocityOpenInterfaceからの移行 - examples/Test_VlocityOpenInterface2Conversion/ —
VlocityOpenInterface2からの移行
出力要件
このスキルで作成する成果物:
<ClassName>.cls—switch on actionによるディスパッチを実装したSystem.Callableの Callable クラス<ClassName>Test.cls— 正常系、異常系、コントラクト、一括処理のテストメソッドを含むテストクラスIndustriesCallableException.cls— カスタム例外クラス(プロジェクトにまだ存在しない場合)
注意事項
- 決定論的で、副作用を考慮した呼び出し可能なアクションを優先します
- アクションの契約は安定させ、破壊的変更には新しいアクションを導入します
- 同期呼び出し可能な処理で長時間実行される作業は避け、必要に応じて非同期処理を使用します
リファレンスファイル一覧
| ファイル | 読むタイミング |
|---|---|
assets/pattern_callable_vanilla.cls | フェーズ 3 — Vanilla System.Callable のスケルトン(フラットな引数、Open Interface との結合なし) |
assets/pattern_callable_openinterface.cls | フェーズ 3 — inputMap/options 引数を持つ System.Callable のスケルトン(Open Interface 互換) |
assets/pattern_openinterface.cls | フェーズ 3 — switch on によるディスパッチと outputMap コントラクトを備えた VlocityOpenInterface2 のスケルトン |
assets/pattern_test_class.cls | フェーズ 4 — テストクラスのスケルトン(正常系、異常系、コントラクト、一括処理、null 引数のケース) |
assets/pattern_migration.cls | 移行 — 注釈付きの移行パターン(VlocityOpenInterface2 → System.Callable) |
examples/Test_QuoteByProductCallable/Industries_QuoteByProductCallable.cls | フェーズ 3 — WITH USER_MODE SOQL とエラーエンベロープを備えた、呼び出し可能な実装の完全な例 |
examples/Test_QuoteByProductCallable/Industries_QuoteByProductCallableTest.cls | フェーズ 4 — 正常系、コントラクト、未対応アクションのケースを網羅した完全なテストクラス |
examples/Test_QuoteByProductCallable/IndustriesCallableException.cls | フェーズ 3 — 未対応アクション向けのカスタム例外パターン |
examples/Test_QuoteByProductCallable/TRANSCRIPT.md | リファレンス — Quote-by-Product の呼び出し可能な実装例に関する推論トランスクリプト |
examples/Test_VlocityOpenInterfaceConversion/MyCustomCallable.cls | フェーズ 3 — レガシー VlocityOpenInterface からの移行パターン |
examples/Test_VlocityOpenInterfaceConversion/MyCustomCallableTest.cls | フェーズ 4 — VlocityOpenInterface の移行例向けテストクラス |
examples/Test_VlocityOpenInterfaceConversion/IndustriesCallableException.cls | フェーズ 3 — VlocityOpenInterface の変換と併せてデプロイするカスタム例外クラス |
examples/Test_VlocityOpenInterfaceConversion/MyCustomVlocityOpenInterface2.cls | フェーズ 3 — 移行前の元のレガシー VlocityOpenInterface2 クラス |
examples/Test_VlocityOpenInterfaceConversion/TRANSCRIPT.md | リファレンス — VlocityOpenInterface の変換に関する推論トランスクリプト |
examples/Test_VlocityOpenInterface2Conversion/MyCustomCallable.cls | フェーズ 3 — VlocityOpenInterface2 からの移行パターン |
examples/Test_VlocityOpenInterface2Conversion/MyCustomCallableTest.cls | フェーズ 4 — VlocityOpenInterface2 の移行例向けテストクラス |
examples/Test_VlocityOpenInterface2Conversion/IndustriesCallableException.cls | フェーズ 3 — VlocityOpenInterface2 の変換と併せてデプロイするカスタム例外クラス |
examples/Test_VlocityOpenInterface2Conversion/MyCustomRemoteClass.cls | フェーズ 3 — VlocityOpenInterface2 の移行例で使用するリモートクラス |
examples/Test_VlocityOpenInterface2Conversion/TRANSCRIPT.md | リファレンス — VlocityOpenInterface2 の変換に関する推論トランスクリプト |