mcpField
P
platform-salesforce-connect-adapter-generate

platform-salesforce-connect-adapter-generate

github.com/forcedotcom开发1.1k346 次安装1 天前更新
代码仓库

关于 platform-salesforce-connect-adapter-generate

用于 Salesforce Connect 的开发技能,可指导构建和部署自定义 Apex 适配器。它会先收集 API 信息,再生成两个 Apex 类、元数据并提供设置步骤。

主要功能

  1. 01生成 Connection 和 Provider Apex 类
  2. 02将 REST 响应映射为外部对象架构
  3. 03支持只读和读写适配器
  4. 04通过 sf CLI 部署类
  5. 05指导手动设置与验证

适用场景

  1. 01将 REST API 数据作为 Salesforce 记录访问
  2. 02构建需认证或公开的自定义适配器
  3. 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 — 自定义 Apex 适配器

引导用户构建完整的自定义 Salesforce Connect Apex 适配器:两个 Apex 类、元数据部署和注册。不要猜测用户的 API 结构——生成前先询问。

范围

**范围内:**生成 DataSource.Connection 和 DataSource.Provider Apex 类、Named Credential 元数据、通过 sf CLI 部署,以及针对任意 REST API 提供分步的 Setup 注册指南。

**范围外:**配置标准适配器(OData、Snowflake、GraphQL——它们有各自的流程)。生成 External Data Source 元数据文件(无法通过 sf CLI 部署——必须在 Setup 中手动注册)。编写通过 Salesforce Connect 框架以外的方式调用外部 API 的 Apex(请使用 platform-apex-generate 或 integration-connectivity-generate 技能)。

开始之前

确认两件事。如果缺少任何一项,请先询问再继续。

1. 这确实是 Salesforce Connect 用例吗?

用户想要……正确的工具
实时查询外部数据而不复制数据——只读或读写,并以 Salesforce 记录的形式显示此技能
按计划将数据复制或同步到 Salesforceplatform-data-manage 技能
连接到 OData、GraphQL、DynamoDB、Athena 或 Cross-Org标准适配器设置——不需要 Apex,使用不同的流程
通过 Salesforce 原生 Snowflake 适配器连接 Snowflake(直接使用 Snowflake 协议)内置 Snowflake 适配器——不需要 Apex
通过 REST 或 HTTP API 访问 Snowflake(或任何数据库)数据此技能——Snowflake REST 端点 → 自定义 Apex 适配器
从 Apex 或 Flow 逻辑调用外部 APIplatform-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 需要一个许可证)。没有许可证时,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、scratch、sandbox)设置 .cls-meta.xml 中的 apiVersion

如果用户提供了 OpenAPI 规范,请提取:

  • 所有返回数组的 GET 端点 → 每个端点对应一个 DataSource.Table
  • 响应对象属性 → DataSource.Column 条目
  • id / uuid / 主键 → 映射到 ExternalId
  • 属性类型 → 使用下方的字段类型映射表

要构建的内容

每个自定义 Salesforce Connect 适配器都恰好由两个 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() 始终只针对一个表操作(QueryContext 只有一个 TableSelection)。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”时调用;返回用于定义 External Object 架构和列的 List<DataSource.Table>

Provider 类会在 Salesforce Setup 的 External Data Source 类型下拉菜单中显示为 Custom-[ClassName]。

**重要:**每次编辑 Connection 类后,都必须再次保存 Provider 类,即使没有更改也一样。否则,适配器会从 Type 选择列表中消失,现有的 External Object 选项卡也会失效。


字段类型映射

外部 API 类型使用此类型
string / textDataSource.DataType.TEXT_TYPE
number / integer / decimalDataSource.DataType.NUMBER_TYPE
booleanDataSource.DataType.BOOLEAN_TYPE
date (ISO 8601)DataSource.DataType.DATE_TYPE
datetime / timestampDataSource.DataType.DATETIME_TYPE
URLDataSource.DataType.URL_TYPE
emailDataSource.DataType.EMAIL_TYPE
phoneDataSource.DataType.PHONE_TYPE
enum / picklistTEXT_TYPE — 将枚举值映射为字符串
nested object / JSON blob展平为标量字段,或使用 TEXT_TYPE 并在 query() 中解析
array派生一个计数字段(NUMBER_TYPE),或展平首个元素的字段
string > 255 chars长文本区域 — 不要截断;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。


场景

共有四种场景:(1) 公共只读,(2) API 密钥/OAuth 身份验证,(3) 支持 upsert/delete 的读写操作,(4) 分页 API。每种场景的完整代码示例见 references/scenarios.md。

各场景的主要区别:

场景身份验证模式额外功能Named Credential
公共只读ANONYMOUSQUERY、SEARCH作为元数据部署
需要身份验证NAMED_PRINCIPAL 或 PER_USERQUERY、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 页面(演示效果最佳,适用于任何 org)

部署一个 Visualforce 页面和 Apex 控制器,查询 [Object]__x 并在 apex:pageBlockTable 中呈现行。通过 [orgUrl]/apex/[PageName] 打开。测试时比列表视图更可靠 — 可绕过选项卡要求、部署状态和筛选器问题。标准模板见 references/scenarios.md。

选项 3 — 列表视图(标准界面,但需要额外步骤)

要让列表视图显示记录,以下四项必须全部满足:

  1. 外部对象部署状态 = 已部署(对象管理器 → 编辑)
  2. 外部对象已创建选项卡(设置 → 选项卡 → 自定义对象选项卡 → 新建)
  3. 列表视图筛选器设为 全部(而非“最近查看”)
  4. 外部 API URL 已配置远程站点设置
故障排查:无错误但记录数为 0
症状原因修复方法
SOQL 返回 0 条记录缺少远程站点设置设置 → 远程站点设置 → 新建
SOQL 返回 0 条记录未找到命名凭证设置 → 命名凭证 → 确认 callout: 名称完全匹配
SOQL 返回 0 条记录组织代理阻止了外部 URL使用回环模式,或切换到外部 DE 组织
列表视图显示 0 条记录部署状态 = 开发中对象管理器 → [Object]__x → 编辑 → 已部署
列表视图显示 0 条记录筛选器为“最近查看”将筛选器改为“全部”
应用程序启动器中没有显示任何内容尚未创建选项卡设置 → 选项卡 → 自定义对象选项卡 → 新建

Agent 部署的内容与开发者手动操作的内容

Agent 部署(执行一条 sf project deploy start 命令)
文件说明
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 会报错:“Could not infer a metadata type.” 告诉用户部署后前往设置 → 外部数据源 → 新建。

正确的 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

结尾始终使用:“部署完成。还差一步:在 Salesforce 设置中打开外部数据源,然后点击‘验证并同步’。”


错误处理规则

绝不能让异常未经捕获就从 query() 中传播出去 — Salesforce 会向用户显示没有上下文信息的通用错误。

情况处理方式
HTTP 401throw new DataSource.OAuthTokenExpiredException()
HTTP 429 / 速率限制返回空行;通过 System.debug() 记录日志
HTTP 500 或网络错误返回空行;不要重新抛出异常
响应中的字段为 nullrecord.get('field') != null ? (String) record.get('field') : ''
无法扁平化的嵌套 JSON将原始 JSON 字符串作为 TEXT_TYPE 字段返回,而不是让整个查询失败

管理器限制

  • 每个事务最多 100 次 HTTP callout — 每次 query() 调用都对应一个事务
  • 堆内存限制为 6 MB(同步)— 不要反序列化超大负载;使用服务端分页
  • CPU 限制为 10 秒 — 避免对大型响应数组使用嵌套循环

设置前提条件 — 严格按此顺序操作

1. 先部署 Apex 类

只有在组织中部署了至少一个 DataSource.Provider 子类后,外部数据源类型下拉列表中才会显示 Salesforce Connect: Custom (Developed with Apex) 类型。

这不是权限问题,而是依赖关系——Salesforce 会在运行时发现可用的 Provider 类。没有已部署的 Provider,下拉列表中就不会显示该选项。

正确顺序——务必遵循:

  1. 先部署 Apex 类(sf project deploy start)
  2. 然后前往 Setup → External Data Sources → New → 此时会显示 Custom Apex 类型

如果用户说“我在下拉列表中看不到 Custom Apex 选项”,答案是:先部署这些类,然后再返回 Setup。

2. 测试前添加 Remote Site Setting

必须将外部 API 的基本 URL 加入白名单,否则调用会静默失败——query() 会返回空行,不会抛出异常,也不会显示错误消息。可将其作为元数据部署,或前往 Setup → Remote Site Settings → New 添加。

3. Validate and Sync 后——将 Deployment Status 设为 Deployed

Validate and Sync 后,Salesforce 会创建状态为 “In Development” 的 External Object。更改此状态之前,列表视图和 SOQL 查询都会返回 0 条记录。不会显示任何错误——这是另一个静默失败。

Setup → Object Manager → [YourObject]__x → Edit
  Deployment Status → Deployed → Save

Validate and Sync 完成后,务必告知用户执行此步骤。

4. 创建选项卡,以便在 App Launcher 中显示 External Object

没有选项卡时,External Object 在 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 类后,在 Setup 中手动注册 External Data Source
使用 upsertRow() 或 deleteRow()(单数)这些方法不存在——会导致编译错误使用 upsertRows() 和 deleteRows()(复数)
只在 Provider 上放置 sync()在某些 API 版本中,sync() 必须位于 Connection 上——编译器会提示在 Connection 上实现 sync();如果报错,则从 Provider 中移除
在 Apex 中硬编码 API URL凭据会暴露在源代码中,调用会被阻止始终使用 callout:NamedCredentialName
从 search() 返回单个 DataSource.TableResultsearch() 返回 List<DataSource.TableResult>——会导致编译错误遍历 context.tableSelections,并为每个表返回一个结果
在 query() 中跳过 COUNT 处理列表视图会发起 COUNT 查询;不检测就会返回错误结果检查 columnsSelected[0].aggregation == DataSource.QueryAggregation.COUNT
将 External Object 保留为“In Development”记录会返回 0 条且没有错误——用户无法看到Validate and Sync 后:Object Manager → [Object]__x → Edit → Deployed
跳过 Remote Site Setting调用会静默执行并返回空行,不会抛出异常部署 remoteSiteSettings/[API].remoteSite-meta.xml,或在 Setup 中手动添加

发布前

确认:已收集输入(API 名称、URL、身份验证、示例响应、写入支持)→ 代码在 Connection 上包含 sync() + query() + search(),在 Provider 上包含 getCapabilities() + getConnection(),每个表都包含 ExternalId 和 nameColumn,query() 中包含 COUNT 处理,测试使用模拟数据,所有端点都带有 callout: 前缀 → 已生成两个 .cls-meta.xml 文件 → 已提供部署命令 → 已告知部署后的步骤(设置 Named Credential、Remote Site Setting、注册 External Data Source、Validate and Sync、将 Deployment Status 设为 Deployed、创建选项卡)。


参考示例

请参阅 references/official-examples.md,了解 Salesforce Connect 官方适配器示例的注释说明,包括 GitHub Issues(完整的 DML、选项列表、跨表关系)、Google Drive(OAuth + 测试模拟)、Google Books(分页)、StackOverflow(多个表)和 Loopback(筛选条件转换)。为新用户生成内容前请先阅读。


项目设置 — 如果开发者还没有 SFDX 项目

部署前,他们需要项目结构。如果尚不存在,请先生成:

sf project generate --name my-adapter --output-dir .
cd my-adapter

这会创建 force-app/main/default/classes/ 和必需的 sfdx-project.json。所有生成的文件都放入此结构中。开发者不需要 VS Code、Agentforce Vibes 或任何 Salesforce IDE,只需安装 sf CLI,并通过 sf org login web --alias my-org 完成组织身份验证。

此技能适用于任何能够读取上下文文件的编码 Agent — Claude Code、Cursor、Windsurf、GitHub Copilot,或任何已加载 SKILL.md 的 Agent。无需 Salesforce MCP 服务、Agentforce Vibes 或 Salesforce 内部工具。


输出格式

按以下顺序生成文件,然后提供部署命令:

  1. force-app/main/default/classes/[API]DataSourceConnection.cls
  2. force-app/main/default/classes/[API]DataSourceProvider.cls
  3. force-app/main/default/classes/[API]DataSourceConnection.cls-meta.xml
  4. force-app/main/default/classes/[API]DataSourceProvider.cls-meta.xml
  5. force-app/main/default/namedCredentials/[API].namedCredential-meta.xml — 仅适用于公共 API

每个 Apex 类顶部都添加一行注释:// Salesforce Connect custom adapter for [API name] 除非逻辑选择不明显,否则不要添加其他行内注释。

评论

支持 Markdown