Corsair Bubble 插件实战指南:通过 Data API 与 Workflow API 连接无代码应用数据
2026/9/16 11:47:32 网站建设 项目流程

Corsair Bubble 插件实战指南:通过 Data API 与 Workflow API 连接无代码应用数据

【免费下载链接】corsairConnect your users to their apps项目地址: https://gitcode.com/GitHub_Trending/corsa/corsair

Bubble 是一款无代码应用构建平台,它提供的 Data API 与 Workflow API 是外部系统读写其数据库、触发其业务流程的标准通道。@corsair-dev/bubble是 Corsair 生态中的 Bubble 插件(位于 packages/bubble),将上述两组 API 封装为 10 个类型安全、带权限分级与错误重试策略的端点。阅读本文后,你将掌握该插件的安装方式、完整端点清单、API Key 认证配置、Bubble 应用名与自定义域名解析规则,以及 Data API 增删改查、批量创建与 Workflow API 调用的底层实现原理。

插件概览与安装

@corsair-dev/bubble是 Corsair 的官方 Bubble 插件,通过 package.json 声明其职责为 "Bubble (Data API & Workflow API) plugin for Corsair"。它依赖corsair >= 0.1.0zod ^4.1.13(后者用于端点的输入输出 Schema 校验),以 ESM 模块形式发布,提供dist/index.js与类型声明dist/index.d.ts

安装命令(项目使用 pnpm workspace 管理):

pnpm add @corsair-dev/bubble

安装后即可在应用代码中导入插件工厂函数bubble(),并将其注册到 Corsair 中。该插件实现位于 packages/bubble/index.ts,整体采用"插件工厂 + 端点树 + Schema + 错误处理器"的结构组织,与仓库中其他插件(如packages/bigmlpackages/slack)保持一致的架构风格。

端点全景:10 个操作与权限分级

Bubble 插件的端点树定义在 packages/bubble/index.ts 的bubbleEndpointsNested中,按things(Data API 数据记录)、workflows(Workflow API 工作流)、meta(元数据)三个命名空间组织。下表完整列出插件暴露的操作、操作 ID、风险等级与说明:

操作操作 ID风险等级说明
meta.getSwaggerbubble.api.meta.getSwaggerread获取已启用 Bubble API 的自动生成 Swagger 2.0 JSON
things.bulkCreatebubble.api.things.bulkCreatewrite一次请求创建最多 1,000 条记录,逐条返回结果
things.createbubble.api.things.createwrite使用给定字段值创建单条记录
things.deletebubble.api.things.deletedestructive按唯一 ID 永久删除记录
things.getbubble.api.things.getread按唯一 ID 获取单条记录
things.listbubble.api.things.listread搜索并分页获取某数据类型的记录,支持约束条件与排序
things.replacebubble.api.things.replacewrite覆盖既有记录的全部可编辑字段(省略的字段重置为默认值)
things.updatebubble.api.things.updatewrite修改既有记录的部分字段
workflows.runbubble.api.workflows.runwrite使用请求体参数运行 API 工作流(Workflow API POST)
workflows.runGetbubble.api.workflows.runGetwrite使用查询字符串参数运行 API 工作流(Workflow API GET)

风险等级(riskLevel)直接服务于 Corsair 的权限系统:read端点(things.getthings.listmeta.getSwagger)默认权限为openwrite端点为allowthings.delete被标记为destructive,需要更高等级的授权。这一点在 packages/bubble/index.ts 的bubbleEndpointMetaBubblePluginOptions.permissions注释中有明确说明。

认证与连接配置

API Key 认证

插件使用 API Key 认证,首次使用时 Corsair 会提示租户提供凭据。认证配置在 packages/bubble/index.ts 的bubbleAuthConfig中定义:

const defaultAuthType = 'api_key' as const satisfies AuthTypes; export const bubbleAuthConfig = { api_key: { account: ['appName'] as const, }, } as const satisfies PluginAuthConfig;

api_key持有的是 Bubble 管理员级 API Token(即编辑器 Settings → API → Private key 中生成的私钥),每次请求都以Authorization: Bearer <token>形式发送。appName是账号级(account-level)字段,用于解析应用的 API 基础 URL。

密钥的获取逻辑位于 packages/bubble/index.ts 的keyBuilder中:如果插件选项显式传入了key,优先使用;否则调用ctx.keys.get_api_key()从账号密钥管理器中读取存储的密钥,读取不到则抛出AuthMissingError('bubble', 'api_key')。值得注意的是,packages/bubble/client.ts 中的tryGetStoredKey对"账号没有 DEK(数据加密密钥)"这一合法状态做了特殊处理——get_api_key()在这种情况下会抛异常而非返回 null,插件会将其解析为"未存储密钥"而非中断请求,只有解密失败、数据库错误等真实运维问题才会继续抛出。

appName 与 baseUrl:解析 API 基础地址

Bubble 的 Data API 与 Workflow API 都挂在应用自己的子域名上(/api/1.1前缀下)。插件通过apiBase函数(见 packages/bubble/client.ts)解析请求的最终来源:

  • 默认情况:使用https://{appName}.bubbleapps.ioappName的解析优先级是"插件选项options.appName优先,否则回退到账号级存储的appName字段"(见 packages/bubble/endpoints/shared.ts 的resolveAppName);
  • 自定义域名部署:通过baseUrl完全覆盖基础 URL,例如https://app.bubbleapps.io/version-test指向开发分支;
  • 安全约束baseUrl必须以https://开头,否则抛出 400 错误("Bubble base URL must use HTTPS so the API token is never sent in plaintext");appName必须是单个 DNS label(字母、数字、连字符),正则APP_NAME_PATTERN = /^a-zA-Z0-9?$/在构造任何来源 URL 之前强制执行,防止恶意构造的appName(如x@evil.example#)把携带 Bearer Token 的请求重定向到其他主机(SSRF 防护)。

插件选项

bubble()工厂函数接受BubblePluginOptions,完整字段如下(类型定义见 packages/bubble/index.ts):

选项类型说明
authType'api_key'认证方式,目前仅支持api_key,默认即为此值
keystringBubble 管理员 API Token(编辑器 Settings → API → Private key),以Authorization: Bearer <token>发送
appNamestringBubble 应用名,解析为https://{appName}.bubbleapps.io;也可作为连接上的账号级字段存储
baseUrlstring完全覆盖基础 URL,用于自定义域名或开发分支(如https://app.bubbleapps.io/version-test
hooks生命周期钩子可选,端点生命周期钩子
errorHandlersCorsairErrorHandler可选,自定义错误处理器(与默认处理器合并)
permissionsPluginPermissionsConfig权限配置,读端点默认open,写端点allowthings.deletedestructive

初始化示例:

import { bubble } from '@corsair-dev/bubble'; const bubblePlugin = bubble({ authType: 'api_key', appName: 'rentalunits', // 或依赖账号级字段,请求时自动解析 // key 也可不传,首次使用时 Corsair 会提示租户提供凭据 });

Data API:Things 端点深度解析

Data API 路径位于https://{appName}.bubbleapps.io/api/1.1/obj/...,实现集中在 packages/bubble/endpoints/things.ts,输入输出 Schema 定义在 packages/bubble/endpoints/types.ts。

things.get:按 ID 读取单条记录

输入为typeName(数据类型名)与thingId(记录唯一 ID),请求GET /obj/{typename}/{uid}。返回的记录使用BubbleThingEntitySchema 校验(见 packages/bubble/schema/database.ts),核心字段包括:

  • _id:记录唯一 ID,读取与列表结果中始终存在;
  • Created By:记录创建者(官方示例为邮箱字符串,可选);
  • Created Date:ISO-8601 创建时间戳(API 1.1 下如2016-11-11T19:14:46.517Z,可选);
  • Modified Date:ISO-8601 修改时间戳,不可写,Bubble 自动更新(可选)。

Schema 使用.loose()允许自定义字段透传——Bubble 数据类型的自定义字段名可以包含空格(如 "Unit name"),这些字段不会因校验被丢弃。读取成功后,插件还会把完整记录缓存到ctx.db.things(见 packages/bubble/endpoints/persist.ts),并通过logEventFromContext记录审计事件bubble.things.get

things.list:搜索、约束与分页

列表端点把 Bubble 的 "Do a search for" 步骤参数原样暴露为输入,请求GET /obj/{typename}。输入字段(Schema 见 packages/bubble/endpoints/types.ts):

字段类型说明
typeNamestring数据类型名
cursornumber(≥0 整数)首条记录的排位(Bubble 的 cursor),用于分页
limitnumber(1–50,000)每页条数;Data API GET 上限 50,000 条(Enterprise 版 10,000,000 条)
constraintsBubbleConstraintSchema[]搜索约束数组,序列化为 JSON 放入constraints查询参数
sortFieldstring排序字段,默认按创建日期
descendingboolean降序排序(Bubble 对文本字段排序通常要求设置此值)
excludeRemainingboolean跳过剩余记录计数(大应用上节省容量)
additionalSortFields{ sortField, descending }[]附加排序字段,同样 JSON 编码进查询串

约束对象BubbleConstraintSchema与编辑器中的搜索条件一一对应:key为字段名,constraint_type取值如equalsgreater thantext containsis_empty等,value为比较值(is_empty/is_not_empty/empty/not empty时可省略,geographic_search允许对象值)。

请求构造时,constraintsadditionalSortFields数组会被JSON.stringify编码进查询串,undefined字段通过compact函数剔除(见 packages/bubble/endpoints/shared.ts),避免序列化出空查询键。响应使用BubbleListResponseSchema:response.cursor(本页首条排位)、response.count(本页条数)、response.remaining(剩余条数,exclude_remaining=true时缺省)、response.results(记录数组)。列表结果同样会批量写入ctx.db.things缓存。

things.create 与 things.bulkCreate:单条与批量创建

  • things.createPOST /obj/{typename},请求体为fields(JSON 对象)。fields通过ThingFieldsSchema校验——必须是 JSON 对象且不允许undefined值(undefined会被JSON.stringify丢弃,导致字段缺失)。响应为{"status":"success","id":"..."}.loose()允许额外字段)。
  • things.bulkCreatePOST /obj/{typename}/bulk,一次创建最多 1,000 条(Schema 强制min(1).max(1000))。Bubble 要求批量请求以text/plain发送、每行一个 JSON 对象,因此插件将每条记录JSON.stringify后以换行符拼接(见 packages/bubble/endpoints/things.ts)。Bubble 可能部分成功部分失败,响应按行解析为{status, id?, message?}数组,逐条返回结果(如{"status":"success","id":"..."}{"status":"error","message":"..."}),解析失败的行降级为{status:'error', message:'Could not parse response line'}。最终输出{count, items}

批量创建允许更长的超时时间:共享请求超时为 20 秒,而BUBBLE_BULK_TIMEOUT_MS = 260_000(约 4.3 分钟)——Bubble 官方允许批量创建运行长达 4 分钟,插件据此放宽限制(见 packages/bubble/client.ts)。

things.update、things.replace 与 things.delete

  • things.updatePATCH /obj/{typename}/{uid}):仅修改传入的字段,未涉及的字段保持原值。响应不含字段值,因此插件会从缓存中驱逐该记录的旧快照(evictEntity),而不是信任部分重写后的脏数据。
  • things.replacePUT /obj/{typename}/{uid}):覆盖全部可编辑字段,省略的字段会被重置为默认/空值——这是 PUT 的语义,官方建议局部写入优先使用things.update
  • things.deleteDELETE /obj/{typename}/{uid}):按 ID 永久删除,风险等级为destructive,同样会驱逐缓存快照并记录审计事件。

things.updatethings.replacethings.delete的输出类型均为void(见 packages/bubble/endpoints/types.ts 的BubbleEndpointOutputs)。

记录镜像(Schema 缓存)

插件声明了版本为1.0.0的数据库 Schema(见 packages/bubble/schema/index.ts),包含things实体。它是尽力而为(best-effort)的镜像:只有经get/list取回的完整记录才会写入缓存;create/bulkCreate只返回 ID,不写缓存;update/replace/delete会驱逐过期快照。这种"只镜像已确认数据、不信任部分重写"的策略保证了缓存数据不会失真。

Workflow API:运行 API 工作流

Workflow API 路径位于https://{appName}.bubbleapps.io/api/1.1/wf/{workflowName},实现见 packages/bubble/endpoints/workflows.ts。

  • workflows.runPOST /wf/{workflowName},参数以 JSON 放入请求体(paramsRecord<string, JSON 值>,可选)。工作流名"没有空格且同时就是 URL 端点",因此会被encodeURIComponent编码后拼入路径。
  • workflows.runGetGET /wf/{workflowName},参数放在查询字符串上(仅支持 string/number/boolean 值,GET 请求没有请求体)。注意:GET 工作流仍然是有副作用的,不可当作幂等读操作重试。

响应由工作流的 "Return data from API" 动作决定(默认是{"status":"success"}JSON 信封),normalizeWorkflowResult会保证status字段存在(缺省时补为'success'),输出 Schema.loose()允许自定义返回数据透传。两个端点都会记录bubble.workflows.run/bubble.workflows.runGet审计事件。

Meta 端点:获取 Swagger 文档

meta.getSwagger在编辑器 Settings → API 中启用 "Swagger file" 后可用,返回自动生成的 Swagger 2.0 JSON(GET /api/1.1/meta/之类路径,输出类型为Record<string, unknown>)。它属于read风险等级,可用于运行时发现/校验 Bubble 数据类型的字段结构,为 Agent 提供结构感知能力。

错误处理与重试策略

插件自带一套基于 HTTP 状态码分类的错误处理器(见 packages/bubble/error-handlers.ts),并与用户自定义处理器合并。底层网络错误统一包装为BubbleAPIError(见 packages/bubble/client.ts),它会从corsair/httpApiError中复制 HTTP 状态、响应体与限流头(retry-after等)——Bubble 的 Data API 错误体形如{"statusCode":..., "body":{...}},Workflow API 形如{"error_class":...},两者结构不同,因此分类只依赖 HTTP 状态码,body保持unknown

各错误类别的重试策略:

错误类别匹配条件重试策略
RATE_LIMIT_ERROR429仅对幂等操作(things.get/list/update/replace/deletemeta.getSwagger)最多重试 5 次、指数退避;创建类/工作流类绝不重放
AUTH_ERROR401不重试
PERMISSION_ERROR403不重试
NOT_FOUND_ERROR404 或消息含 "not found"不重试
SERVER_ERROR5xx仅对非"不安全写"操作最多重试 3 次、指数退避
DEFAULT兜底不重试

设计要点:isIdempotentisUnsafeWrite两个判定函数把"可能已在服务端生效"的写操作(things.createthings.bulkCreateworkflows.runworkflows.runGet)从所有重试路径中排除——5xx 时请求可能从未到达 Bubble,也可能已被处理只是响应丢失,重试第二种情况会重复执行业务。而传输层的BUBBLE_RATE_LIMIT_CONFIGmaxRetries设为 0,429 的重试完全交给错误处理器决策,从机制上保证 POST 创建与工作流永远不会被自动重放。

Webhooks:为什么不支持

插件明确声明不支持 Webhooks(README 中 "No webhooks")。原因在 packages/bubble/index.ts 的注释中讲得很清楚:Bubble 的 Data API 与 Workflow API 是拉取式(pull-based)出站调用,不存在可订阅的签名入站事件流,因此bubbleWebhooksNested为空对象、pluginWebhookMatcherundefined。如果需要监听 Bubble 数据变化,应由应用侧通过定时轮询things.list或在工作流中主动推送来实现。

测试与验证

插件配套了完整的测试套件(位于 packages/bubble),包括:

  • client.test.ts:客户端请求构造、appName 校验、baseUrl 强制 HTTPS 等逻辑的单元测试;
  • operations.test.ts:各端点操作行为测试;
  • error-handlers.test.ts:错误分类与重试策略测试(验证 429/5xx 对幂等与非幂等操作的差异化处理);
  • integration.test.ts:真实环境的集成测试(通过pnpm test:live运行,jest --testPathIgnorePatterns=/node_modules/ --testPathPattern=integration);
  • schema.test.ts:Schema 校验测试。

这些测试可直接运行pnpm test验证,为"哪些操作可安全重试、哪些绝不重放"等关键行为提供了可执行依据。

小结

@corsair-dev/bubble将 Bubble 的 Data API 与 Workflow API 收敛为一套类型安全、权限分级、重试策略完备的插件能力:10 个端点覆盖记录级增删改查、1,000 条批量创建、约束搜索与 API 工作流触发;API Key 认证配合appName/baseUrl双通道来源解析,兼顾了标准子域名、自定义域名与开发分支三类部署形态;在错误处理上,通过"幂等可重试、写操作不重放"的严格边界,规避了重复创建与重复执行工作流的风险。对希望为终端用户打通 Bubble 无代码应用数据的开发者而言,这是接入 Corsair 生态最直接、最规范的方式。

【免费下载链接】corsairConnect your users to their apps项目地址: https://gitcode.com/GitHub_Trending/corsa/corsair

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询