优化 Salesforce API 调用:咨询顾问利用复合 API 提升性能并降低集成复杂性的指南

背景与应用场景

在 Salesforce 实施和集成项目中,我们作为 Salesforce 咨询顾问,经常会遇到外部系统需要与 Salesforce 进行数据交互的场景。这些交互往往涉及创建、更新或查询多个相关联的 Salesforce 对象(SObject),例如,在创建客户(Account)的同时创建其关联的联系人(Contact),或者在处理订单(Order)时同时处理多个订单商品(Order Item)。在传统方式下,这通常意味着外部系统需要向 Salesforce 发送多个独立的 API 调用,每处理一个对象或一个操作就需要一次网络往返(round trip)。

这种一对一的 API 调用模式虽然直观,但在面对复杂业务流程和大量数据时,会带来显著的性能问题和效率瓶颈。首先,大量的网络请求会增加延迟,降低整体响应速度。其次,Salesforce 对外部 API 调用有严格的限制,即所谓的“API 调用限制”(API Call Limits)或“Governor Limits”。频繁的单次调用很容易触及这些限制,导致集成失败或服务中断,这对于需要稳定运行的业务系统是不可接受的。

作为一名咨询顾问,我们的职责不仅是实现功能,更要为客户提供健壮、高效且具备未来可扩展性的解决方案。因此,我们必须寻找更优的集成策略。而 Salesforce 复合 API(Composite API)正是应对这些挑战的强大工具之一。它允许我们将多个独立的 REST API 请求打包成一个单一的请求发送到 Salesforce,从而大幅减少网络往返次数,优化性能,并有效降低触及 API 调用限制的风险。

复合 API 的典型应用场景包括:

  • 批量创建或更新相关记录:例如,从外部 ERP 系统导入一个完整的销售订单,包含订单头和多个订单行项目。使用复合 API 可以一次性创建所有记录。
  • 事务性操作:需要确保一系列操作“全部成功或全部失败”(all-or-none)的场景,以维护数据完整性。例如,创建客户及其关联的联系人,如果其中任何一个操作失败,所有操作都应回滚。
  • 依赖性操作链:某些操作的输入依赖于前一个操作的输出。例如,先创建一个父级记录,然后利用其新生成的 ID 来创建或关联子级记录。
  • 减少网络延迟:对于地理位置距离 Salesforce 数据中心较远的外部系统,减少网络往返可以显著提升用户体验和系统响应速度。
  • 简化集成逻辑:将复杂的业务逻辑封装在一个 API 调用中,减少外部系统集成代码的复杂性。

原理说明

Salesforce 复合 API(Composite API)是一个强大的 REST API 资源,它允许开发者在一个单一的请求中执行一系列独立的 REST API 请求。其核心思想是将多个子请求(subrequests)封装在一个主请求体中,发送给 Salesforce。Salesforce 接收到主请求后,会按顺序处理其中的每个子请求,并将所有子请求的结果打包在一个单一的响应中返回给调用方。

工作机制

复合 API 的工作机制可以概括为以下几点:

  1. 单一网络请求:外部系统只需发送一个 HTTP 请求到 Salesforce 的 `/services/data/vXX.0/composite` 或其他复合 API 端点,而不是为每个操作发送一个单独的请求。这极大地减少了网络开销和延迟。
  2. 子请求列表:主请求的请求体(Request Body)包含一个 `compositeRequest` 数组,数组中的每个元素都是一个独立的子请求。每个子请求可以指定不同的 HTTP 方法(POST, GET, PATCH, DELETE)、不同的 URL 和不同的请求体。
  3. 引用 ID(ReferenceId):这是复合 API 的一个关键特性。每个子请求都可以被分配一个唯一的 `referenceId`。这个 `referenceId` 允许后续的子请求引用前一个子请求的结果。例如,如果第一个子请求创建了一个 Account 记录,其生成的 Account ID 可以通过 `@{{referenceId}.id}` 的格式在后续的子请求中被引用,用于创建关联的 Contact 记录。这种机制使得复合 API 能够处理有依赖关系的操作链。
  4. 事务性(Transactionality):复合 API 支持事务性操作。通过设置 `allOrNone` 标志为 `true`,可以确保所有子请求要么全部成功,要么全部失败。如果任何一个子请求失败,整个复合请求将被回滚,所有已执行的更改都将被撤销,从而保证了数据的一致性和完整性。这是在处理复杂业务逻辑时非常重要的特性,可以有效防止部分数据写入导致的脏数据问题。
  5. API 限制:虽然复合 API 减少了网络往返,但每个子请求仍会消耗 Salesforce 内部的资源,并计入相应的 Governor Limits,例如 DML 语句限制、SOQL 查询限制等。然而,整个复合请求只算作一次外部 API 调用,这对于那些有严格 API 调用次数限制的集成来说是一个巨大的优势。

复合 API 资源类型

Salesforce 提供了几种不同类型的复合 API 资源,以适应不同的集成需求:
  • 通用复合 API (`/services/data/vXX.0/composite`)

    这是最通用的复合 API 端点,它允许在单个请求中执行多达 25 个子请求。这些子请求可以涉及不同的对象类型,使用不同的 HTTP 方法(POST、GET、PATCH、DELETE),并且可以通过 `referenceId` 进行链式操作。它支持事务性(`allOrNone` 标志)。

  • 复合树 API (`/services/data/vXX.0/composite/tree/{sObjectApiName}`)

    复合树 API 专门用于一次性创建具有多层父子关系的记录(Parent-Child Relationships)。它支持最多 5 层深度和每个请求最多 200 条记录的创建。此 API 强制要求事务性,即所有记录要么全部创建成功,要么全部失败。它的请求结构更侧重于表示树状数据,通过嵌套的 `records` 数组来表示子记录。例如,可以在一个请求中创建 Account 及其关联的多个 Contact 记录。

  • 复合批处理 API (`/services/data/vXX.0/composite/batch`)

    与通用复合 API 类似,它也允许在单个请求中执行多个子请求。但是,它不提供事务性保证(每个子请求独立成功或失败),也不支持 `referenceId` 进行链式操作。它适用于需要批量执行独立操作,且不需要严格事务性或操作间依赖的场景。最大子请求数量同样是 25 个。

  • 复合图 API (`/services/data/vXX.0/composite/graph`)

    复合图 API 是为更复杂的场景设计的,它允许您在单个请求中对多个对象执行更复杂的、类似图结构的 CRUD 操作。它提供了更细粒度的控制,支持事务组,并且可以处理更复杂的依赖关系。此 API 通常用于高度复杂的集成场景,以确保多个相互关联的业务对象能够在一个原子操作中被一致地处理。目前,其最大子请求数量为 500。

作为咨询顾问,我们通常会根据客户的具体业务需求、数据结构和性能要求,选择最合适的复合 API 类型。对于简单的父子关系创建,复合树 API 是首选;对于更通用的、有依赖关系的操作链,通用复合 API 是理想选择。


示例代码

以下示例将展示如何使用通用复合 API (`/services/data/vXX.0/composite`) 和复合树 API (`/services/data/vXX.0/composite/tree/{sObjectApiName}`) 来执行常见的集成任务。所有代码示例均基于 Salesforce 官方文档提供的方式。

示例 1:通用复合 API - 创建账户及关联联系人

这个示例展示了如何在一个复合请求中,首先创建一条新的 Account(客户)记录,然后利用新创建的 Account 的 ID 来创建一条关联的 Contact(联系人)记录。这体现了 `referenceId` 的强大功能,实现了操作链。

# 通用复合 API - 创建 Account 和一个关联的 Contact
# 源自: Salesforce REST API Developer Guide (v59.0 示例)
# URL: /services/data/vXX.0/composite
#
# 请替换 YOUR_INSTANCE.salesforce.com 为您的 Salesforce 实例 URL
# 请替换 YOUR_ACCESS_TOKEN 为您的 OAuth 2.0 访问令牌
curl -X POST "https://YOUR_INSTANCE.salesforce.com/services/data/v59.0/composite" \
-H "Authorization: Bearer YOUR_ACCESS_TOKEN" \
-H "Content-Type: application/json" \
-d '{
    "allOrNone": true,
    "compositeRequest": [
        {
            "method": "POST",
            "url": "/services/data/v59.0/sobjects/Account",
            "referenceId": "refAccount",
            "body": {
                "Name": "Sample Account from Composite"
            }
        },
        {
            "method": "POST",
            "url": "/services/data/v59.0/sobjects/Contact",
            "referenceId": "refContact",
            "body": {
                "LastName": "Smith",
                "AccountId": "@{refAccount.id}"
            }
        }
    ]
}'

代码说明:

  • `allOrNone: true`:此设置确保整个复合请求是事务性的。如果 Account 或 Contact 的创建有任何一个失败,整个操作都将回滚,不会在 Salesforce 中留下任何部分创建的记录。这是保证数据完整性的关键。
  • `compositeRequest`:这是一个数组,包含了所有需要执行的子请求。
  • 第一个子请求 (Account)
    • `"method": "POST"`:指定 HTTP 方法为创建记录。
    • `"url": "/services/data/v59.0/sobjects/Account"`:指定要操作的 Salesforce 对象 API 名称。
    • `"referenceId": "refAccount"`:为这个子请求指定一个唯一的引用 ID。这个 ID 在后续的子请求中用于引用此操作的结果。
    • `"body": {"Name": "Sample Account from Composite"}`:请求体包含了创建 Account 记录所需的数据。
  • 第二个子请求 (Contact)
    • `"method": "POST"`:同样是创建记录。
    • `"url": "/services/data/v59.0/sobjects/Contact"`:指定要操作的 Salesforce 对象 API 名称。
    • `"referenceId": "refContact"`:为 Contact 创建操作指定一个引用 ID。
    • `"body": {"LastName": "Smith", "AccountId": "@{refAccount.id}"}`:请求体包含了创建 Contact 记录所需的数据。这里最关键的是 `AccountId: "@{refAccount.id}"`,它使用了第一个子请求的 `referenceId` (`refAccount`) 来动态获取新创建 Account 的 ID,并将其赋值给 Contact 的 `AccountId` 字段,从而建立了联系人与客户之间的关联。

示例 2:复合树 API - 创建账户及其多个联系人

这个示例展示了如何使用复合树 API 在一个请求中创建一条 Account 记录和与它关联的多个 Contact 记录。复合树 API 针对这种父子关系的批量创建进行了优化,其请求结构也更直观地反映了层级关系。

# 复合树 API - 创建 Account 并关联多个 Contacts
# 源自: Salesforce REST API Developer Guide (v59.0 示例)
# URL: /services/data/vXX.0/composite/tree/Account
#
# 请替换 YOUR_INSTANCE.salesforce.com 为您的 Salesforce 实例 URL
# 请替换 YOUR_ACCESS_TOKEN 为您的 OAuth 2.0 访问令牌
curl -X POST "https://YOUR_INSTANCE.salesforce.com/services/data/v59.0/composite/tree/Account" \
-H "Authorization: Bearer YOUR_ACCESS_TOKEN" \
-H "Content-Type: application/json" \
-d '{
  "records": [
    {
      "attributes": { "type": "Account", "referenceId": "refAccount1" },
      "Name": "Sample Account for Composite Tree Demo",
      "Contacts": {
        "records": [
          {
            "attributes": { "type": "Contact", "referenceId": "refContact1" },
            "FirstName": "John",
            "LastName": "Doe",
            "Title": "CEO"
          },
          {
            "attributes": { "type": "Contact", "referenceId": "refContact2" },
            "FirstName": "Jane",
            "LastName": "Doe",
            "Title": "VP"
          }
        ]
      }
    }
  ]
}'

代码说明:

  • URL `/services/data/v59.0/composite/tree/Account`:注意 URL 的不同,它明确指定了根对象类型为 `Account`。
  • `records`:这是一个数组,包含了要创建的所有父级记录。
  • 父级记录 (Account)
    • `"attributes": { "type": "Account", "referenceId": "refAccount1" }`:定义了记录的类型和引用 ID。
    • `"Name": "Sample Account for Composite Tree Demo"`:Account 的名称。
    • `"Contacts": {...}`:这是一个嵌套的 JSON 对象,表示与该 Account 关联的子级 Contact 记录。
  • 子级记录 (Contacts)
    • `"Contacts": {"records": [...]}`:在 `Contacts` 对象内部,又有一个 `records` 数组,其中包含了所有要创建的 Contact 记录。Salesforce 会自动将这些 Contact 记录与它们的父级 Account 关联起来。
    • 每个 Contact 记录也通过其 `attributes` 定义类型和引用 ID。
    • `"FirstName"`, `"LastName"`, `"Title"`:包含 Contact 记录的详细信息。

复合树 API 自动处理了父子记录之间的关联逻辑,使得批量创建层级数据变得非常简洁和高效。


注意事项

作为 Salesforce 咨询顾问,在推荐和实施复合 API 时,我们需要向客户和开发团队明确以下关键注意事项,以确保集成的健壮性、安全性和可维护性。

权限(Permissions)

这是集成成功的基石。执行复合 API 请求的用户或集成用户必须拥有对所有涉及对象和字段的正确权限。这意味着:

  • 对于创建(POST)操作,用户需要有对象的“创建”权限和相关字段的“编辑”权限。
  • 对于更新(PATCH)操作,用户需要有对象的“编辑”权限和相关字段的“编辑”权限。
  • 对于查询(GET)操作,用户需要有对象的“读取”权限和相关字段的“读取”权限。
  • 对于删除(DELETE)操作,用户需要有对象的“删除”权限。

如果任何一个子请求因为权限不足而失败,并且 `allOrNone` 设置为 `true`,则整个复合请求都会失败并回滚。因此,在部署前务必进行彻底的权限测试。

API 限制(API Limits)

虽然复合 API 将多个请求合并为一个 HTTP 请求,从而减少了外部 API 调用次数(通常一个复合请求只算作一次 API 调用),但每个子请求仍会消耗 Salesforce 内部的 Governor Limits。例如:

  • DML 语句限制:每个子请求中的 DML 操作都会计入总的 DML 限制(例如,在单个事务中最多 150 条 DML 语句)。
  • SOQL 查询限制:每个子请求中的查询操作都会计入总的 SOQL 查询限制(例如,在单个事务中最多 100 条 SOQL 查询)。
  • CPU 时间限制、堆大小限制等同样适用。

最大子请求数量也是一个限制:通用复合 API 每次最多包含 25 个子请求,复合树 API 每次最多创建 200 条记录(最多 5 层深度),复合图 API 每次最多 500 个子请求。过度复杂的单个复合请求可能仍然会因为内部资源消耗过大而超时或失败。因此,需要权衡在一个复合请求中包含多少操作,避免“一口吃个胖子”。

错误处理(Error Handling)

复合 API 的响应体包含了每个子请求的详细结果。即使整个复合请求成功(HTTP 状态码 200),也需要解析响应来检查每个子请求是否成功。特别是在 `allOrNone: false` 的情况下,某些子请求可能会成功,而另一些则失败。

响应通常会包含一个 `compositeResponse` 数组(或 `results` 数组),其中每个元素对应一个子请求。每个元素会包含 `httpStatusCode`、`body`(成功时包含记录 ID,失败时包含错误信息)、`referenceId` 等。集成系统必须设计健壮的错误处理逻辑,能够根据这些信息识别失败的子请求,并采取相应的重试或日志记录措施。

性能考量(Performance Considerations)

虽然复合 API 通常能提升性能,但并不意味着它在所有情况下都是最佳选择。对于需要处理的记录数量非常庞大(例如,数万到数十万条记录)的批量数据加载场景,考虑使用 Salesforce 的批量 API(Bulk API),它专为高吞吐量设计,并能更好地处理异步操作和大文件。

此外,一个过于庞大或包含过多复杂逻辑的复合请求可能会因为内部处理时间过长而导致超时。务必在实际环境中对复合 API 的性能进行充分测试。

事务性(Transactionality)

通用复合 API 的 `allOrNone` 标志和复合树 API 的固有事务性,为数据完整性提供了强有力的保障。但这意味着如果某个子请求因数据验证、权限或其他原因失败,所有在此复合请求中已执行的 DML 操作都将被回滚。在设计集成时,需要充分理解这一行为,并确保业务逻辑能够接受这种“全部成功或全部失败”的模式。对于不需要事务性,且子请求之间无依赖关系的场景,复合批处理 API 或多个独立 API 调用可能更合适。

调试(Debugging)

由于多个操作被捆绑在一起,调试复合 API 请求可能会比调试单个 API 请求更具挑战性。通过仔细检查响应体中每个子请求的 `httpStatusCode` 和 `body` 信息,可以定位问题。使用 `referenceId` 也能帮助追踪特定操作的流程和结果。在开发阶段,可以先用较少的子请求进行测试,逐步增加复杂度。

API 版本控制(API Versioning)

确保您的复合 API 请求中指定的 API 版本是最新的或与您的 Salesforce 组织兼容。例如,示例中使用的 `v59.0`。Salesforce 会定期发布新版本,旧版本可能会在未来被弃用。


总结与最佳实践

作为 Salesforce 咨询顾问,我们深知为客户提供高效、可靠且可维护的集成解决方案的重要性。复合 API 无疑是 Salesforce 集成工具箱中的一把利器,它通过将多个 API 调用捆绑为一个请求,带来了显著的优势:

  • 提升性能:大幅减少网络往返次数,降低集成延迟,加快数据交互速度。
  • 降低 API 调用限制风险:一个复合请求仅计为一次外部 API 调用,有效延长了 API 调用额度,避免因频繁调用而触发限制。
  • 简化集成逻辑:外部系统无需管理复杂的依赖关系或多次握手,只需构建一个结构化的请求即可完成复杂业务流程。
  • 增强数据完整性:通过 `allOrNone` 事务性保证,确保相关联的数据操作要么全部成功,要么全部失败,避免了不完整或不一致的数据状态。

最佳实践:

  1. 选择合适的复合 API 类型
    • 对于创建具有父子关系的记录,优先使用复合树 API (`/composite/tree`),它效率更高且结构更清晰。
    • 对于需要链式操作(即一个请求的输出作为下一个请求的输入)且涉及不同对象类型的复杂逻辑,使用通用复合 API (`/composite`) 并充分利用 `referenceId`。
    • 对于无需事务性、无依赖关系的批量独立操作,考虑复合批处理 API (`/composite/batch`)。
    • 对于更复杂的图状依赖和多事务组场景,考虑复合图 API (`/composite/graph`)。
  2. 设计健壮的错误处理机制:即便请求的 HTTP 状态码为 200,也要仔细解析响应体中的每个子请求结果。实现日志记录、通知和重试逻辑,以应对部分或全部失败的情况。
  3. 合理规划子请求数量:虽然复合 API 允许捆绑多个请求,但每个子请求仍会消耗内部资源。避免创建过大或过于复杂的单个复合请求,尤其是在通用复合 API 中,建议保持在 25 个子请求的限制内。对于复合树,也应关注 200 条记录的限制。
  4. 充分测试权限:在开发和部署的各个阶段,使用集成用户的身份对复合 API 请求进行彻底的权限测试,确保所有涉及对象和字段的访问权限都已正确配置。
  5. 监控 API 使用情况:定期检查 Salesforce 的“设置”>“API 使用情况报告”或使用事件监控(Event Monitoring)来跟踪 API 调用模式和限额使用情况,及时发现潜在的瓶颈。
  6. 版本管理与未来兼容性:始终使用最新或经过充分测试的 API 版本。在进行 Salesforce 升级或集成系统升级时,重新验证复合 API 的功能。

复合 API 是 Salesforce 为集成复杂业务流程提供的强大解决方案。作为咨询顾问,我们应深入理解其工作原理、不同类型及其各自的优缺点,并结合客户的实际需求,明智地选择和实施。通过遵循上述最佳实践,我们可以帮助客户构建出高性能、高效率、高可靠性的 Salesforce 集成方案,真正实现业务价值。

评论

此博客中的热门博文

Salesforce Experience Cloud 技术深度解析:构建社区站点 (Community Sites)

Salesforce 登录取证:深入解析用户访问监控与安全

Salesforce Data Loader 全方位指南:数据迁移与管理的最佳实践