platform-salesforce-connect-adapter-generate について
Salesforce Connect 向けのカスタム Apex アダプターの作成とデプロイを案内する開発スキルです。API 情報を確認してから、2つの Apex クラスとメタデータを生成し、設定手順を示します。
主な機能
- 01Connection と Provider の Apex クラス生成
- 02REST 応答を外部オブジェクトのスキーマに対応
- 03読み取り専用・読み書きアダプターに対応
- 04sf CLI によるクラスのデプロイ
- 05手動設定と検証の案内
活用シーン
- 01REST API データを Salesforce レコードとして公開
- 02認証あり・なしのカスタムアダプター構築
- 03ページネーションを使う外部データアクセスの設定
インストール
コマンドをコピーしてターミナルで実行します。
npx skills add https:/ / github.com/ forcedotcom/ sf-skills --skill platform-salesforce-connect-adapter-generateインストール後、Claude Code で/platform-salesforce-connect-adapter-generateを入力して読み込まれたか確認します。
同梱ファイルreferences/official-examples.mdreferences/scenarios.md
詳細
Salesforce Connect — Custom Apex Adapter
ユーザーが、2 つの Apex クラス、メタデータのデプロイ、登録を含む、完全な Salesforce Connect カスタム Apex アダプターを構築できるよう案内します。ユーザーの API の仕様を推測してはいけません。生成を始める前に質問してください。
対象範囲
対象: DataSource.Connection と DataSource.Provider の Apex クラスの生成、Named Credential メタデータ、sf CLI によるデプロイ、あらゆる REST API のセットアップ登録に関する手順ごとのガイダンス。
対象外: 標準アダプター(OData、Snowflake、GraphQL)の設定(それぞれに独自の手順があります)。External Data Source メタデータファイルの生成(sf CLI ではデプロイできないため、Setup で手動登録する必要があります)。Salesforce Connect フレームワーク外で外部 API を呼び出す Apex の作成(platform-apex-generate または integration-connectivity-generate スキルを使用してください)。
開始前
2 つの点を確認してください。どちらかが不明な場合は、先に質問してください。
1. これは本当に Salesforce Connect のユースケースですか?
| ユーザーがしたいこと… | 適切なツール |
|---|---|
| 外部データをコピーせずにリアルタイムでクエリする — 読み取り専用または読み書き可能で、Salesforce レコードとして表示される | このスキル |
| データを Salesforce に定期的にコピーまたは同期する | platform-data-manage スキル |
| OData、GraphQL、DynamoDB、Athena、または Cross-Org に接続する | 標準アダプターのセットアップ — Apex は不要で、手順も異なります |
| Salesforce のネイティブ Snowflake アダプター(Snowflake プロトコルに直接接続)経由で Snowflake に接続する | 組み込みの Snowflake アダプター — Apex は不要です |
| REST または HTTP API 経由で Snowflake(または任意のデータベース)のデータにアクセスする | このスキル — Snowflake REST エンドポイント → カスタム Apex アダプター |
| Apex または Flow のロジックから外部 API を呼び出す | platform-apex-generate スキルまたは integration-connectivity-generate |
| Salesforce データを外部システムに公開する | integration-connectivity-generate |
| リアルタイムでプッシュされたデータを受信する、または外部イベントをサブスクライブする | Salesforce Connect ではありません — Connect はプル専用です。代わりに Platform Events または Change Data Capture を使用してください |
| 分析または一括処理のためにデータを同期またはコピーする | Data Cloud または ETL — Connect はゼロコピーの仮想化専用です |
標準アダプターが利用できる場合は、そのことをユーザーに伝えてください。標準アダプターで対応できるのにカスタムアダプターを作成するのは、不要な作業です。
2. Salesforce Connect ライセンスを持っていますか?
カスタムアダプターには Salesforce Connect ライセンスが必要です(External Data Source ごとに 1 ライセンス)。ライセンスがない場合、External Data Source メニューに Apex オプションは表示されません。ユーザーがライセンスを持っていない場合は、先にそのことを伝えてください。
デフォルトの組織コンテキスト(ローカルで実行する場合)
ユーザーが組織エイリアスを指定しない場合は、demo-org を使用します。
ユーザーが SFDX プロジェクトのパスを指定しない場合は、~/salesforce-connect-apex-skill/sfconnect-demo/ を使用します。
これらはローカルテスト用のデフォルト値です。ユーザーが独自の値を指定した場合は、必ずそちらを優先してください。
生成前に入力情報を収集する
以下の情報なしにコードを生成してはいけません。不足しているものがあれば質問してください。
| 入力 | 重要な理由 |
|---|---|
| API 名とその機能 | クラス名を決定し、フィールドマッピングのコンテキストを設定します |
| ベース URL | Named Credential のエンドポイントになります |
| 認証タイプ | Named Credential の設定と getAuthenticationMode() を決定します |
| 主な GET エンドポイントとサンプルレスポンス | External Object のスキーマ(フィールド名、型、ネスト構造)を定義します |
| 書き込みサポートが必要か | upsertRows() と deleteRows() を実装するかどうかを決定します |
| 組織の種類(DE、スクラッチ、Sandbox) | .cls-meta.xml の apiVersion を設定します |
ユーザーが OpenAPI 仕様を提供した場合は、以下を抽出してください。
- 配列を返すすべての GET エンドポイント → それぞれが
DataSource.Tableになります - レスポンスオブジェクトのプロパティ →
DataSource.Columnエントリになります id/uuid/主キー →ExternalIdにマッピングします- プロパティの型 → 下記のフィールド型マッピング表を使用します
作成するもの
すべてのカスタム Salesforce Connect アダプターは、正確に 2 つの Apex クラスで構成されます。
DataSource.Connection
外部 API との通信を処理します。正確なシグネチャは次のとおりです。
override global DataSource.TableResult query(DataSource.QueryContext context)
override global List<DataSource.TableResult> search(DataSource.SearchContext context)
// Write support — only if API supports it:
global override List<DataSource.UpsertResult> upsertRows(DataSource.UpsertContext context)
global override List<DataSource.DeleteResult> deleteRows(DataSource.DeleteContext context)
重要な違い:query() は常に1 つのテーブルを対象にします(QueryContext には TableSelection が 1 つだけあります)。search() は複数のテーブルを同時に対象にできます(SearchContext には複数の TableSelection インスタンスがあります)。それぞれをループで処理し、テーブルごとに結果を返してください。
DataSource.Provider
アダプターの機能とスキーマを Salesforce に宣言します。必須メソッドは次のとおりです。
getAuthenticationMode()— パブリック API の場合はANONYMOUS、認証が必要な API の場合はNAMED_PRINCIPALまたはPER_USERを返しますgetCapabilities()—QUERY、SEARCHを宣言します。書き込みを実装する場合に限り、ROW_CREATE、ROW_UPDATE、ROW_DELETEを追加しますgetConnection(ConnectionParams params)—new YourConnection(params)を返しますsync()— Setup でユーザーが「Validate and Sync」をクリックしたときに呼び出されます。外部オブジェクトのスキーマと列を定義するList<DataSource.Table>を返します
Provider クラスは Salesforce Setup の External Data Source タイプのドロップダウンに Custom-[ClassName] として表示されます。
重要: Connection クラスを編集するたびに、変更がなくても Provider クラスも再保存する必要があります。そうしないと、アダプターが Type ピックリストから消え、既存の External Object タブが機能しなくなります。
フィールド型のマッピング
| 外部 API の型 | 使用する型 |
|---|---|
| string / text | DataSource.DataType.TEXT_TYPE |
| number / integer / decimal | DataSource.DataType.NUMBER_TYPE |
| boolean | DataSource.DataType.BOOLEAN_TYPE |
| date (ISO 8601) | DataSource.DataType.DATE_TYPE |
| datetime / timestamp | DataSource.DataType.DATETIME_TYPE |
| URL | DataSource.DataType.URL_TYPE |
DataSource.DataType.EMAIL_TYPE | |
| phone | DataSource.DataType.PHONE_TYPE |
| enum / picklist | TEXT_TYPE — enum 値を文字列としてマッピングします |
| ネストされたオブジェクト / JSON blob | スカラー項目にフラット化するか、TEXT_TYPE にして query() で解析します |
| array | 件数フィールド(NUMBER_TYPE)を導出するか、最初の要素のフィールドにフラット化します |
| 255 文字を超える string | 長テキストエリア — 切り詰めないでください。Salesforce が自動的にマッピングします |
すべての DataSource.Table に次の列を含める必要があります。
DataSource.Column.text('ExternalId', 255) // unique key from external system — REQUIRED
DataSource.Column.text('Name', 255) // display label shown in Salesforce UI — REQUIRED
DataSource.Column.url('DisplayUrl') // link to the record in the external system — recommended
ExternalId がないことは、アダプターのデプロイは成功してもレコードが表示されない最も一般的な原因です。
DisplayUrl を設定すると、リストビューにクリック可能なリンクアイコンが表示されます。外部レコードの URL を設定してください。
シナリオ
シナリオは 4 つあります:(1)パブリックな読み取り専用、(2)API キー/OAuth による認証、(3)upsert/delete による読み書き、(4)ページネーション対応 API。それぞれのコードパターン全体は references/scenarios.md にあります。
シナリオごとの主な違い:
| シナリオ | 認証モード | 追加機能 | Named Credential |
|---|---|---|---|
| パブリックな読み取り専用 | ANONYMOUS | QUERY、SEARCH | メタデータとしてデプロイ |
| 認証あり | NAMED_PRINCIPAL または PER_USER | QUERY、SEARCH | Setup で手動作成 — 認証情報をメタデータとしてデプロイしないでください |
| 読み書き | ANONYMOUS または認証あり | ROW_CREATE、ROW_UPDATE、ROW_DELETE を追加 | 上記に従う |
| ページネーション対応 | 任意 | 任意 | context.tableSelection.numberOfRows を使用します(null の場合はデフォルトで 500)。queryMore は自動実行されません |
アダプターの動作確認方法
オプション 1 — sf CLI 経由の SOQL(最速、UI 不要)
sf data query \
--query "SELECT ExternalId, Name__c FROM [YourObject]__x LIMIT 5" \
--target-org [org-alias]
行が返されれば、アダプターは動作しています。0 行の場合は、以下のトラブルシューティング手順を確認してください。
オプション 2 — Visualforce ページ(デモに最適、どの組織でも動作)
[Object]__x をクエリして行を apex:pageBlockTable に表示する Visualforce ページと Apex コントローラーをデプロイします。[orgUrl]/apex/[PageName] で開きます。タブの要件、デプロイ状況、フィルターの問題を回避できるため、テストにはリストビューよりも信頼性があります。標準テンプレートは references/scenarios.md を参照してください。
オプション 3 — リストビュー(標準 UI ですが、追加の手順が必要です)
リストビューにレコードを表示するには、次の 4 つすべてを満たす必要があります。
- 外部オブジェクトのデプロイ状況が デプロイ済み である(オブジェクトマネージャー → 編集)
- 外部オブジェクトのタブが存在する(設定 → タブ → カスタムオブジェクトタブ → 新規)
- リストビューのフィルターが すべて に設定されている(「最近参照した項目」ではない)
- 外部 API の URL に対するリモートサイト設定が存在する
トラブルシューティング:エラーなしでレコードが 0 件
| 症状 | 原因 | 修正方法 |
|---|---|---|
| SOQL の結果が 0 件 | リモートサイト設定がない | 設定 → リモートサイト設定 → 新規 |
| SOQL の結果が 0 件 | 名前付き認証情報が見つからない | 設定 → 名前付き認証情報 → callout: の名前が完全に一致することを確認 |
| SOQL の結果が 0 件 | 組織のプロキシが外部 URL をブロックしている | ループバックパターンを使用するか、外部 DE 組織に切り替える |
| リストビューに 0 件表示される | デプロイ状況が「開発中」になっている | オブジェクトマネージャー → [Object]__x → 編集 → デプロイ済み |
| リストビューに 0 件表示される | フィルターが「最近参照した項目」になっている | フィルターを「すべて」に変更 |
| アプリケーションランチャーに何も表示されない | タブが作成されていない | 設定 → タブ → カスタムオブジェクトタブ → 新規 |
エージェントがデプロイするものと、開発者が手動で行うこと
エージェントがデプロイするもの(sf project deploy start コマンド 1 つ)
| ファイル | 備考 |
|---|---|
classes/[API]DataSourceConnection.cls + メタデータ | 常に |
classes/[API]DataSourceProvider.cls + メタデータ | 常に |
namedCredentials/[API].namedCredential-meta.xml | 公開 API のみ — 認証情報が必要な API ではスキップ |
externalDataSources/[API].externalDataSource-meta.xml は生成しないでください。 Apex クラスをデプロイした後、設定で外部データソースを手動登録する必要があります。sf project deploy start コマンドでは、カスタム Apex 外部データソースをデプロイできません。sf CLI は「メタデータ型を推測できません」というエラーを返します。デプロイ後に設定 → 外部データソース → 新規に移動するよう、ユーザーに案内してください。
正しい NamedCredential XML 形式(<name> 要素なし — API 名はファイル名から取得されます):
<?xml version="1.0" encoding="UTF-8"?>
<NamedCredential xmlns="http://soap.sforce.com/2006/04/metadata">
<label>My API</label>
<endpoint>https://api.example.com</endpoint>
<allowMergeFieldsInBody>false</allowMergeFieldsInBody>
<allowMergeFieldsInHeader>false</allowMergeFieldsInHeader>
<generateAuthorizationHeader>false</generateAuthorizationHeader>
<principalType>Anonymous</principalType>
<protocol>NoAuthentication</protocol>
</NamedCredential>
デプロイコマンド:
sf project deploy start \
--source-dir force-app/main/default/ \
--target-org [org-alias]
開発者が手動で行うこと(常に必要 — 対応するメタデータがありません)
検証と同期では、外部 API を呼び出してスキーマを検出し、外部オブジェクト定義を作成します。これはスクリプト化できません。
Setup → External Data Sources → [your data source] → Validate and Sync
Check the box next to each External Object → Sync
App Launcher → search [External Object name] → confirm records appear
必ず最後に次のように記載してください:「デプロイが完了しました。あと 1 つだけ手順があります。Salesforce の設定で外部データソースを開き、[検証と同期]をクリックしてください。」
エラー処理のルール
query() から例外を捕捉されないまま伝播させないでください。Salesforce はコンテキストを示さず、ユーザーに汎用エラーを表示します。
| 状況 | 対処方法 |
|---|---|
| HTTP 401 | throw new DataSource.OAuthTokenExpiredException() |
| HTTP 429/レート制限 | 空の行を返し、System.debug() でログに記録 |
| HTTP 500 またはネットワークエラー | 空の行を返し、再スローしない |
| 応答内のフィールドが null | record.get('field') != null ? (String) record.get('field') : '' |
| フラット化できないネストされた JSON | クエリ全体を失敗させず、TEXT_TYPE フィールドとして生の JSON 文字列を返す |
ガバナー制限
- トランザクションあたり最大 100 回の HTTP コールアウト —
query()の呼び出しごとに 1 つのトランザクションです - ヒープ制限は 6 MB(同期)— 巨大なペイロードをデシリアライズせず、サーバー側のページネーションを使用してください
- CPU 制限は 10 秒 — 大きな応答配列に対するネストされたループは避けてください
前提となる設定 — 必ずこの順序で行ってください
1. Apex クラスを先にデプロイする
Salesforce Connect: Custom (Developed with Apex) タイプは、少なくとも 1 つの DataSource.Provider サブクラスが組織にデプロイされた後にのみ、外部データソースのタイプのドロップダウンに表示されます。
これは権限の問題ではありません。依存関係によるものです。Salesforce は実行時に利用可能な Provider クラスを検出します。Provider がデプロイされていなければ、ドロップダウンに選択肢は表示されません。
常に次の正しい手順で進めてください。
- まず Apex クラスをデプロイします(
sf project deploy start) - 次に「設定」→「外部データソース」→「新規」へ移動すると、カスタム Apex タイプが表示されます
ユーザーが「ドロップダウンにカスタム Apex の選択肢が表示されない」と言った場合は、まずクラスをデプロイしてから、設定に戻るよう案内してください。
2. テスト前にリモートサイトの設定を追加する
外部 API のベース URL はホワイトリストに登録する必要があります。登録しないと、コールアウトはエラーも例外も表示せずに失敗します。query() は空の行を返します。メタデータとしてデプロイするか、「設定」→「リモートサイトの設定」→「新規」で追加してください。
3. Validate and Sync の後に、Deployment Status を Deployed に設定する
Validate and Sync の後、Salesforce はステータスが "In Development" の外部オブジェクトを作成します。この設定を変更するまで、リストビューと SOQL ではレコードが 0 件返されます。エラーは表示されず、これもまたサイレントな失敗です。
Setup → Object Manager → [YourObject]__x → Edit
Deployment Status → Deployed → Save
Validate and Sync が完了したら、必ずこの手順をユーザーに伝えてください。
4. 外部オブジェクトをアプリケーションランチャーに表示するタブを作成する
タブがないと、外部オブジェクトは UI に表示されません。次の場所で作成してください。
Setup → Tabs → Custom Object Tabs → New → select [YourObject]__x → Save
こちらも必要です
- Salesforce Connect ライセンス — ライセンスがない場合、OData を含むすべての Connect アダプタータイプが非表示になります。ドロップダウンに OData と Cross-Org が表示される場合は、ライセンスはすでに有効です。
アンチパターン
| しないこと | 理由 | すること |
|---|---|---|
| API の仕様を把握せずにコードを生成する | フィールドタイプの誤り、ExternalId のマッピングミス、アダプターの不具合につながります | まず API 名、ベース URL、認証タイプ、サンプルレスポンスを確認します |
| ExternalDataSource をメタデータとしてデプロイする | デプロイ可能なメタデータタイプではないため、sf CLI でエラーになります | Apex クラスをデプロイした後、設定で外部データソースを手動で登録します |
upsertRow() または deleteRow()(単数形)を使用する | これらのメソッドは存在せず、コンパイルエラーになります | upsertRows() と deleteRows()(複数形)を使用します |
sync() を Provider だけに実装する | 一部の API バージョンでは sync() を Connection に実装する必要があり、コンパイラーがエラーを通知します | Connection に sync() を実装し、エラーが出る場合は Provider から削除します |
| Apex に API URL をハードコードする | ソースコードから認証情報が漏れ、コールアウトがブロックされます | 常に callout:NamedCredentialName を使用します |
search() から単一の DataSource.TableResult を返す | search() は List<DataSource.TableResult> を返すため、コンパイルエラーになります | context.tableSelections をループして、テーブルごとに 1 つの結果を返します |
query() で COUNT の処理を省略する | リストビューは COUNT クエリを実行するため、検出しないと誤った結果が返されます | columnsSelected[0].aggregation == DataSource.QueryAggregation.COUNT を確認します |
| 外部オブジェクトを "In Development" のままにする | エラーなしでレコードが 0 件返され、ユーザーには見えません | Validate and Sync の後に、「オブジェクトマネージャー」→ [Object]__x →「編集」→「Deployed」の順に操作します |
| リモートサイトの設定を省略する | コールアウトはエラーなく実行されたように見えますが、空の行を返します | remoteSiteSettings/[API].remoteSite-meta.xml をデプロイするか、設定で手動で追加します |
リリース前の確認事項
次の点を確認してください。必要な入力情報(API 名、URL、認証、サンプルレスポンス、書き込みのサポート)を収集済み → コードでは Connection に sync() + query() + search()、Provider に getCapabilities() + getConnection() を実装し、すべてのテーブルに ExternalId と nameColumn を設定し、query() で COUNT を処理し、テスト用のモックデータを用意し、すべてのエンドポイントに callout: プレフィックスを付与済み → 両方の .cls-meta.xml ファイルを生成済み → デプロイコマンドを提示済み → デプロイ後の手順(Named Credential の設定、リモートサイトの設定、外部データソースの登録、Validate and Sync、Deployment Status → Deployed、タブの作成)を伝達済み。
リファレンス例
Salesforce Connect アダプターの公式サンプル(GitHub Issues(完全な DML、選択リスト、テーブル間のリレーション)、Google Drive(OAuth +テスト用モック)、Google Books(ページネーション)、StackOverflow(複数のテーブル)、Loopback(フィルター変換))の注釈付き解説については、references/official-examples.md を参照してください。新しいユーザー向けに生成する前に読んでください。
プロジェクトのセットアップ — 開発者がまだ SFDX プロジェクトを持っていない場合
デプロイする前に、プロジェクト構造が必要です。まだ存在しない場合は、まず生成してください。
sf project generate --name my-adapter --output-dir .
cd my-adapter
これにより、force-app/main/default/classes/ と必要な sfdx-project.json が作成されます。生成されたファイルはすべてこの構造に配置します。開発者に必要なのは、sf CLI がインストールされていることと、sf org login web --alias my-org で組織に認証済みであることだけです。VS Code、Agentforce Vibes、Salesforce IDE は必要ありません。
このスキルは、コンテキストファイルを読み取れるあらゆるコーディングエージェントで動作します。Claude Code、Cursor、Windsurf、GitHub Copilot、または SKILL.md が読み込まれたあらゆるエージェントに対応しています。Salesforce MCP サーバー、Agentforce Vibes、Salesforce 内部ツールは必要ありません。
出力形式
次の順序でファイルを生成し、その後にデプロイコマンドを提示してください。
force-app/main/default/classes/[API]DataSourceConnection.clsforce-app/main/default/classes/[API]DataSourceProvider.clsforce-app/main/default/classes/[API]DataSourceConnection.cls-meta.xmlforce-app/main/default/classes/[API]DataSourceProvider.cls-meta.xmlforce-app/main/default/namedCredentials/[API].namedCredential-meta.xml— 公開 API のみ
各 Apex クラスの先頭に 1 行のコメントを記載します:// Salesforce Connect custom adapter for [API name]
ロジック上の選択が自明でない場合を除き、その他のインラインコメントは記載しないでください。