Salesforce Composite API:实现高效集成的终极指南
身份:Salesforce 集成工程师
背景与应用场景
作为一名 Salesforce 集成工程师,我的日常工作核心是构建稳定、高效且可扩展的桥梁,连接 Salesforce 与外部系统。在这些集成场景中,最常见的挑战之一就是如何处理复杂的、有依赖关系的数据操作,同时还要最小化网络延迟和 API 调用次数。传统的集成模式通常需要对 Salesforce 发起一连串独立的 REST API (表述性状态传递应用程序接口) 调用。例如,创建一个新的客户(Account),然后为该客户创建多个联系人(Contact),最后再创建一个关联的机会(Opportunity)。这个过程至少需要三次独立的网络往返(round-trips),每一次往返都会带来网络延迟,并消耗宝贵的 API 调用限额。
更重要的是,这种串行调用的方式缺乏事务性。如果在创建联系人时发生错误,那么已经成功创建的客户记录就会变成一个“孤儿”数据,破坏了数据的完整性。处理这种部分成功的场景需要复杂的客户端逻辑来进行回滚或补偿操作,这极大地增加了集成方案的复杂性和维护成本。
为了解决这些痛点,Salesforce 提供了 Composite API (组合 API)。这是一个强大的 REST API 资源,它允许我们将多个独立的 API 请求捆绑在一个单一的 HTTP 调用中。这就像是为 API 调用提供了一个批处理和事务控制的“超级容器”。
典型的应用场景包括:
- 初始数据迁移: 当需要从旧系统迁移数据到 Salesforce 时,往往需要同时创建具有父子关系的记录,如 Account 及其下的多个 Contact。使用 Composite API 可以一次性创建整个对象图,大大提高迁移效率。
- 订单处理集成: 当外部电商平台传来一个新订单时,可能需要在 Salesforce 中同时创建一个 Account、一个 Contact、一个 Order 以及多个 Order Line Item。Composite API 可以保证这一系列操作的原子性,要么全部成功,要么全部失败,确保了订单数据的完整性。
- 复杂的 UI 交互: 在一个自定义的前端应用中,用户可能在一个表单里提交了需要更新多个不同对象的信息。前端可以直接构造一个 Composite API 请求,一次性将所有变更提交到 Salesforce,简化了前端逻辑并提升了用户体验。
对于我们集成工程师来说,Composite API 不仅仅是一个技术工具,更是一种优化集成架构、提升系统健壮性和性能的关键策略。
原理说明
Composite API 的核心原理是“请求聚合”与“依赖解析”。它通过一个统一的入口 /services/data/vXX.X/composite
接收一个精心构造的 JSON (JavaScript 对象表示法) 请求体。这个请求体内部包含了一个子请求(subrequest)的集合。
一个典型的 Composite API 请求体结构如下:
{ "allOrNone" : boolean, "compositeRequest" : [{ "method" : "HTTP_METHOD", "url" : "SUBREQUEST_URL", "referenceId" : "REFERENCE_ID", "body" : { ... } }, { ... }] }
关键组成部分解析:
- allOrNone:这是一个布尔类型的标志,也是 Composite API 的精髓所在。
- 当设置为
true
时,整个 Composite 请求将以事务模式执行。这意味着其中任何一个子请求失败,整个事务都会被回滚,所有已经执行成功的子请求所做出的更改都将被撤销。这确保了操作的原子性(Atomicity),对于需要保证数据一致性的业务场景至关重要。 - 当设置为
false
时,每个子请求都是独立执行的。即使某个子请求失败,其他子请求依然会继续处理。这适用于那些允许部分成功的场景,例如批量更新一组互不相干的记录。
- 当设置为
- compositeRequest:这是一个 JSON 数组,其中每个元素都是一个独立的子请求对象。Salesforce 会按照数组中的顺序依次处理这些子请求。一个 Composite API 调用最多可以包含 25 个子请求。
- 子请求对象(Subrequest Object):
method
:标准的 HTTP 方法,如 GET、POST、PATCH、DELETE。url
:子请求的目标 URL,它是一个相对 Salesforce 实例的 REST API 路径。例如/services/data/v58.0/sobjects/Account
。referenceId
:这是一个用户定义的、在当前 Composite 请求范围内唯一的字符串。它的作用是为子请求命名,以便后续的子请求可以引用它。这是实现请求间依赖关系的关键。body
:子请求的请求体,与调用独立的 REST API 时的请求体格式完全相同。例如,在创建一个 Account 时,这里会包含 Account 的字段和值。
子请求之间的依赖关系
Composite API 最强大的功能之一是能够处理子请求之间的依赖关系。例如,我们需要先创建一个 Account,然后立即用这个新 Account 的 ID 去创建一个关联的 Contact。在传统的 API 调用模式下,我们必须等待第一个请求(创建 Account)的响应,拿到 ID 后再发起第二个请求。
使用 Composite API,我们可以通过 引用 ID (reference ID) 语法来优雅地解决这个问题。在第二个子请求中,我们可以使用 @{referenceId.id}
的语法来引用第一个子请求成功创建后返回的记录 ID。Salesforce 在处理时会自动解析这种依赖关系,将第一个请求的结果注入到第二个请求中。
例如,如果第一个创建 Account 的子请求的 referenceId
是 "newAccount"
,那么在第二个创建 Contact 的子请求的 body 中,我们可以这样设置 AccountId
:"AccountId" : "@{newAccount.id}"
。服务器端的执行引擎会确保在执行第二个请求时,@{newAccount.id}
已经被替换为真实的 Account ID。
返回的响应体(Response Body)结构与请求体相对应,它包含一个 compositeResponse
数组,数组中的每个元素都是对应子请求的执行结果,包含了 HTTP 状态码、响应头和响应体。
示例代码
以下是一个非常经典的官方示例,它演示了如何在一个 Composite API 调用中同时创建一个 Account 和一个关联的 Contact。这个例子完美地展示了 referenceId
的用法。
请求 (Request)
这个请求将首先创建一个名为 "Salesforce" 的新客户,然后立即创建一个名为 "John Doe" 的联系人,并将其关联到刚刚创建的客户上。
{ "allOrNone" : true, "compositeRequest" : [{ "method" : "POST", "url" : "/services/data/v58.0/sobjects/Account", "referenceId" : "refAccount", "body" : { "Name" : "Salesforce" } }, { "method" : "POST", "url" : "/services/data/v58.0/sobjects/Contact", "referenceId" : "refContact", "body" : { "LastName" : "Doe", "FirstName" : "John", "AccountId" : "@{refAccount.id}" } }] }
代码注释:
- "allOrNone" : true: 这确保了整个操作的事务性。如果创建 Account 成功但创建 Contact 失败(例如,因为某个必填字段缺失),那么已经创建的 Account 记录将被自动回滚。
- 第一个子请求:
"method" : "POST"
和"url" : "/services/data/v58.0/sobjects/Account"
表明这是一个创建 Account 记录的操作。"referenceId" : "refAccount"
为这个子请求指定了一个引用 ID,我们将其命名为 "refAccount"。"body" : { "Name" : "Salesforce" }
定义了要创建的 Account 的名称。
- 第二个子请求:
"method" : "POST"
和"url" : "/services/data/v58.0/sobjects/Contact"
表明这是一个创建 Contact 记录的操作。"referenceId" : "refContact"
为这个子请求指定了引用 ID。"body" : { ... }
定义了 Contact 的信息。- "AccountId" : "@{refAccount.id}": 这是关键所在。这里使用了引用语法,
@{refAccount.id}
会被 Salesforce 动态替换为第一个子请求(即referenceId
为 "refAccount" 的请求)成功执行后返回的记录 ID。这就在两个独立的创建操作之间建立了关联。
响应 (Response)
如果整个请求成功执行,你将收到一个 HTTP 状态码为 200 OK 的响应,其响应体如下:
{ "compositeResponse" : [{ "body" : { "id" : "001xx000003DHP0AAO", "success" : true, "errors" : [ ] }, "httpHeaders" : { "Location" : "/services/data/v58.0/sobjects/Account/001xx000003DHP0AAO" }, "httpStatusCode" : 201, "referenceId" : "refAccount" }, { "body" : { "id" : "003xx000002BmorAAC", "success" : true, "errors" : [ ] }, "httpHeaders" : { "Location" : "/services/data/v58.0/sobjects/Contact/003xx000002BmorAAC" }, "httpStatusCode" : 201, "referenceId" : "refContact" }] }
代码注释:
- "compositeResponse" : [...]: 这是一个数组,其元素与请求中的
compositeRequest
数组一一对应。 - 第一个响应元素(对应 "refAccount"):
"httpStatusCode" : 201
表示记录创建成功(Created)。"body"
中包含了新创建的 Account 记录的 ID ("001xx000003DHP0AAO")。"referenceId" : "refAccount"
表明这个响应对应于哪个子请求。
- 第二个响应元素(对应 "refContact"):
"httpStatusCode" : 201
同样表示创建成功。"body"
中包含了新创建的 Contact 记录的 ID ("003xx000002BmorAAC")。
注意事项
作为集成工程师,在设计和实现基于 Composite API 的解决方案时,必须考虑以下几点:
- 权限与安全 (Permissions and Security): Composite API 的调用遵循运行用户的权限设置。这意味着执行请求的用户必须对所有子请求中涉及的对象和字段拥有相应的 CRUD (Create, Read, Update, Delete) 权限和 FLS (Field-Level Security)。如果任何一个子请求因为权限不足而失败,它将影响整个事务(当
allOrNone=true
时)。 - API 限制 (API Limits):
- 子请求数量: 单个 Composite API 请求最多只能包含 25 个子请求。如果需要处理超过 25 个操作,你需要将它们分批到多个 Composite API 调用中。
- API 调用计数: 无论内部包含多少个子请求,一次 Composite API 调用只消耗一个 API 调用限额。这是它相对于独立调用的最大优势之一,尤其是在 API 调用量受限的环境中。
- 数据大小限制: 整个请求的 JSON 体大小以及响应的 JSON 体大小都受到限制。请查阅最新的 Salesforce Developer Limits and Allocations Quick Reference 指南以获取具体数值。
- 不支持的 API: 并非所有的 REST API 资源都能作为子请求在 Composite API 中使用。例如,你不能在子请求中调用 Bulk API 或 Streaming API。它主要支持 sObject 相关的操作(CRUD)、Query、Search 等。
- 错误处理 (Error Handling): 错误处理的逻辑高度依赖于
allOrNone
标志。- allOrNone = true: 任何一个子请求失败,整个请求会返回一个 HTTP 400 (Bad Request) 状态码。你需要检查响应体中失败的那个子请求的
body
,其中会包含详细的错误信息。此时,你可以确定 Salesforce 端没有发生任何数据变更。 - allOrNone = false: 整个请求会返回一个 HTTP 200 (OK) 状态码,即使内部有子请求失败。你必须遍历
compositeResponse
数组,逐个检查每个子响应的httpStatusCode
(成功的通常是 2xx,失败的则是 4xx 或 5xx),并根据业务需求进行相应的补偿或日志记录。
- allOrNone = true: 任何一个子请求失败,整个请求会返回一个 HTTP 400 (Bad Request) 状态码。你需要检查响应体中失败的那个子请求的
- 执行顺序和依赖: Salesforce 保证子请求会按照它们在
compositeRequest
数组中出现的顺序执行。因此,在设计有依赖关系的请求时,必须将被依赖的请求(如创建 Account)放在依赖它的请求(如创建 Contact)之前。
总结与最佳实践
Composite API 是 Salesforce 平台提供给集成工程师的一把“瑞士军刀”。它通过将多个 API 调用打包成一个请求,极大地提升了集成效率,减少了网络开销,并提供了强大的事务控制能力。
作为一名集成工程师,我总结的最佳实践如下:
- 优先用于强关联操作: 当你需要执行一系列逻辑上紧密耦合、有先后顺序的操作时,Composite API 是首选方案。例如,创建订单及其明细,或者处理一个包含主从关系的数据实体。
- 明智地选择 `allOrNone`: 根据业务需求来决定是否需要事务性。对于需要保证数据“全有或全无”的场景(如金融交易、订单创建),请务必使用
allOrNone=true
。对于批量更新独立记录等允许部分成功的场景,可以使用allOrNone=false
来提高吞吐量。 - 构建健壮的客户端: 你的客户端代码(无论是中间件还是前端应用)必须能够解析 Composite API 的复杂响应结构。它需要能够处理整体成功、整体失败(
allOrNone=true
)以及部分成功(allOrNone=false
)这三种情况,并做出正确的响应。 - 监控 API 使用情况: 虽然 Composite API 节省了调用次数,但它仍然处理大量数据并执行复杂逻辑。要密切关注 API 限制、CPU 时间等 Governor Limits,确保集成方案不会对 Salesforce 组织性能产生负面影响。
- 了解其替代方案: Composite API 非常适合处理中等数量(最多 25 个)的记录。对于需要处理成千上万条记录的大规模数据加载或更新,Bulk API 2.0 可能是更合适的选择。对于更复杂的、涉及多个分支和条件逻辑的事务,可以考虑使用 Apex REST 自定义端点来实现。了解并选择正确的工具是成功集成的关键。
总之,熟练掌握并恰当使用 Composite API,可以显著简化集成逻辑、提升性能和数据一致性,是每一位 Salesforce 集成工程师必备的核心技能。
评论
发表评论