mcpField
B
building-omnistudio-callable-apex

building-omnistudio-callable-apex

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

关于 building-omnistudio-callable-apex

用于创建、审查和迁移基于 System.Callable 的 Salesforce Industries 可调用 Apex 技能,面向集成 OmniStudio 扩展点的开发者,强调明确的操作契约、安全数据访问、一致响应和测试覆盖。

主要功能

  1. 01生成 System.Callable 实现
  2. 02审查可调用代码风险
  3. 03迁移旧版 Vlocity 接口
  4. 04定义操作与响应契约
  5. 05落实 CRUD/FLS 和共享安全
  6. 06按 120 分量表验证

适用场景

  1. 01实现 OmniStudio 可调用操作
  2. 02将 VlocityOpenInterface 类现代化
  3. 03测试输入契约和批量处理

安装

复制下面的命令,在终端中运行。

$npx skills add https://github.com/forcedotcom/sf-skills --skill building-omnistudio-callable-apex

安装后在 Claude Code 中输入/building-omnistudio-callable-apex确认已加载。

包含的文件

除 SKILL.md 外,安装时一起下载的参考资料和脚本。

CREDITS.md
README.md
assets/
pattern_callable_openinterface.cls
pattern_callable_vanilla.cls
pattern_migration.cls
pattern_openinterface.cls
pattern_test_class.cls
examples/Test_QuoteByProductCallable/
Industries_QuoteByProductCallable.cls
Industries_QuoteByProductCallableTest.cls
IndustriesCallableException.cls
TRANSCRIPT.md
examples/Test_VlocityOpenInterface2Conversion/
IndustriesCallableException.cls
MyCustomCallable.cls
MyCustomCallableTest.cls
MyCustomRemoteClass.cls
TRANSCRIPT.md
examples/Test_VlocityOpenInterfaceConversion/
IndustriesCallableException.cls
MyCustomCallable.cls
MyCustomCallableTest.cls
MyCustomVlocityOpenInterface2.cls
TRANSCRIPT.md

详细介绍

building-omnistudio-callable-apex:Salesforce Industries Common Core 的 Callable Apex

专注于 Salesforce Industries Common Core 的 Callable Apex 实现。编写安全、确定且可配置的 Apex,确保与 OmniStudio 和 Industries 扩展点顺畅集成。

范围

  • 范围内:为 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)

核心职责

  1. 生成 Callable:构建具有安全操作分派机制的 System.Callable 类
  2. 审查 Callable:审计现有 Callable 实现的正确性和风险
  3. 验证与评分:根据 120 分制评分标准进行评估
  4. 适配 Industries:确保兼容 OmniStudio/Industries 扩展点

工作流(4 阶段模式)

阶段 1:收集需求

询问:

  • 入口点(OmniScript、Integration Procedure、DataRaptor 或其他 Industries 挂钩)
  • 操作名称(传递给 call 的字符串)
  • 输入/输出约定(必需键、类型和响应结构)
  • 数据访问需求(对象/字段、CRUD/FLS(创建/读取/更新/删除和字段级安全)规则)
  • 副作用(DML、调用、异步要求)

然后:

  1. 扫描现有 Callable 类:Glob: **/*Callable*.cls
  2. 确定 Industries 扩展使用的共享工具类或基类
  3. 创建任务列表

阶段 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:实现模式

原生 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 设为空 Map。

实现规则:

  1. 保持 call() 精简;委托给私有方法或服务类
  2. 尽早验证并转换输入类型(安全处理 null)
  3. 强制执行 CRUD/FLS(创建/读取/更新/删除和字段级安全)及共享规则(with sharing、Security.stripInaccessible())
  4. 当 args 包含记录集合时进行批量化处理
  5. 适当时在 SOQL 中使用 WITH USER_MODE
  6. 命名空间处理: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——其中包含完整的 VlocityOpenInterface2 骨架,以及使用 switch on 进行分发和 outputMap 契约的示例。

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验证必需键;安全地转换类型;空值保护
安全性20with 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 绑定到同一操作同一时间只能启用一个入口点;确认 Callable 正常工作后,停用旧接口

常见反模式

  • call() 包含业务逻辑,而不是委派处理
  • 操作名称没有版本号或未记录
  • 假定输入映射包含所需键,却不进行检查
  • 响应类型混杂(有时是 Map,有时是 String)
  • 未测试不支持的操作

跨技能集成

技能使用时机示例
generating-apex可调用实现以外的一般 Apex 工作“为 Account 创建触发器”
generating-custom-object / generating-custom-field编码前确认对象/字段是否可用“描述 Product2 字段”
deploying-metadata验证/部署可调用类“部署到 sandbox”

参考技能

请使用以下位置的核心 Apex 标准、测试模式和防护措施:


随附示例

输出要求

此技能生成的交付物:

  • <ClassName>.cls — 实现 System.Callable 并使用 switch on action 进行分发的 Callable 类
  • <ClassName>Test.cls — 包含正向、负向、契约和批量测试方法的测试类
  • IndustriesCallableException.cls — 自定义异常类(如果项目中尚不存在)

说明

  • 优先选择确定性强、能感知副作用的可调用操作
  • 保持操作契约稳定;对于破坏性变更,应引入新操作
  • 避免在同步可调用项中执行长时间运行的工作;需要时使用异步方式

参考文件索引

文件阅读时机
assets/pattern_callable_vanilla.cls第 3 阶段——纯 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 阶段——测试类框架(涵盖正向、负向、契约、批量和空参数用例)
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参考——按产品报价可调用示例的推理记录
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 转换的推理记录

评论

支持 Markdown