mcpField
O
objectstack-api

objectstack-api

github.com/objectstack-ai开发76229 次安装今天更新
代码仓库

关于 objectstack-api

objectstack-api 是用于设计和编写 ObjectStack HTTP API 的技能,面向 ObjectStack 开发者,涵盖自动生成的数据路由、声明式端点、访问策略及端点约束。

主要功能

  1. 01对象的自动生成 REST 路由
  2. 02通过 apis 声明端点
  3. 03API 方法与访问策略指引
  4. 04端点映射和命名规则
  5. 05公开表单端点约定

适用场景

  1. 01设计 ObjectStack 对象的 CRUD 和查询路由
  2. 02声明委托给数据或流程管线的端点
  3. 03检查匿名表单提交和端点访问
  4. 04升级含声明式 API 定义的堆栈

安装

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

$npx skills add https://github.com/objectstack-ai/objectstack --skill objectstack-api

安装后在 Claude Code 中输入/objectstack-api确认已加载。

附带文件references/_index.mdevals/endpoints-auth-routes.json

详细介绍

API 设计 — ObjectStack API 协议

技能边界

需求改用
对象、字段、权限或数据源objectstack-data
筛选、排序、分页或聚合请求objectstack-query
注册内核服务,或从插件读取内核服务objectstack-platform
路由守卫或身份验证谓词中的 CELobjectstack-formula

自动生成的 API 与自定义 API

自动生成的 API

每个 apiEnabled: true(默认值)的 ObjectStack 对象都会自动获得完整的 REST API:

GET    /api/v1/data/{object}          # List records (with filter, sort, pagination)
GET    /api/v1/data/{object}/:id      # Get single record
POST   /api/v1/data/{object}          # Create record
PATCH  /api/v1/data/{object}/:id      # Update record
DELETE /api/v1/data/{object}/:id      # Delete record (hard delete)
POST   /api/v1/data/{object}/query    # Complex queries + aggregation (QueryAST in body)
POST   /api/v1/data/{object}/batch    # Per-object batch operations
POST   /api/v1/batch                  # Cross-object atomic batch

数据 CRUD 位于 /data 前缀下。没有 /bulk 路由,也没有 GET .../aggregate 路由——批量写入通过 batch 端点进行,聚合则通过 POST /api/v1/data/{object}/query 进行,请求体中包含 groupBy/aggregations。

关键规则: 如果对象定义了 apiMethods,则只会公开这些操作(以及由它们派生的内容);[] 表示拒绝所有操作。可配置的值是六种基本操作——请参阅 API 方法(操作)。

元数据 API(/meta)

元数据读取接口位于 /api/v1/meta 下(与上文的数据 CRUD 路由分开):

GET /api/v1/meta/:type            # List metadata items of a type (object, view, flow, doc, …)
GET /api/v1/meta/:type/:name      # Read a single metadata item

读取端的查询参数(?preview=draft、?package=、?include=content)是客户端契约——任何 stack 都不会声明这些参数。

公共(匿名)表单端点

只有当 FormView 的 sharing 同时声明以下三项时,匿名表单端点才会提供该表单:enabled: true(架构默认值为 false)、allowAnonymous: true 和 publicLink slug。只要缺少任何一项,两个端点都会返回 404 FORM_NOT_FOUND。之后,表单会挂载在:

GET  /api/v1/forms/:slug         # returns form spec + restricted objectSchema
POST /api/v1/forms/:slug/submit  # whitelist-filtered INSERT, no auth header

这些端点会绕过 enforceAuth(Web-to-Lead / Web-to-Case 工作流)。表单自身的声明授权提交操作:在其目标对象上授予 publicFormGrant(仅可创建并回读新行,不包含其他操作),且该授权会在解析任何权限集之前确定。提交上下文中的 guest_portal 名称本身不授予任何权限,也不需要权限集;同名权限集仅会影响授权结果的遮罩器。框架会剥离表单 sections[].fields[] 列表之外的字段;目标对象上的 beforeInsert 钩子应写入安全的默认值(status='new'、lead_source='web'、……),并 delete 特权键(owner、internal_notes、……)。在受限模式(group/isolated)下,如果对象受组织列限制,该对象上的表单也会被屏蔽——两个端点都会返回 404,保存/发布时会发出 public-form-intake-unavailable 警告;如果对象的行不属于任何组织,可为其声明 tenancy: { enabled: false },以重新开放表单。完整契约请参阅 node_modules/@objectstack/spec/src/ui/view.zod.ts(FormViewSchema)和 node_modules/@objectstack/spec/src/ui/sharing.zod.ts(包含 enabled / allowAnonymous / publicLink 的 SharingConfigSchema)。


声明式端点(apis:)——无需处理器代码

defineStack({ apis }) 会将 HTTP 端点声明为元数据。声明式端点从协议 17 起即可使用:运行时会匹配 METHOD + path,执行端点的策略键,并委派给内置路由使用的同一套管线——object_operation 委派给 /api/v1/data/{object} 后方的数据管线,flow 委派给 POST /api/v1/automation/{name}/trigger 后方的自动化管线。端点是稳定的 URL 加上现有管线之上的策略层,绝不是第二种执行方式。

在 apis: 和代码处理器之间做选择
用途适用情况
defineStack({ apis })端点是平台已经执行的某项功能的投影:查询并返回记录,或触发工作流。不需要代码,也没有部署产物,受发布门禁控制。优先选择此方式。
运行代码的工作流端点需要真正的处理器代码:将 type: 'flow' 端点指向一个工作流,该工作流的 script 节点命名一个栈函数(defineStack({ functions })),或其 connector_action 节点调用一个已声明的连接器(出站)。URL 保持声明式;代码在自动化界面原本运行代码的位置执行。

由你控制的发送方发起的入站 Webhook 属于 type: 'api' 工作流 (objectstack-automation → 入站 Webhook(api)触发器):它会验证 ObjectStack 自身的 x-objectstack-signature,将请求加入队列,并返回 202。 应用绝不会挂载到 http.server 上——该服务是平台插件自有的建门原语,而通过代码挂载的路由不会获得调用方身份、身份验证门禁、速率限制、命名空间划分或 OpenAPI 条目。目前有三种情况没有应用界面;请如实说明,不要凭空编造:通过原始请求体上的自有签名验证的第三方回调(钩子只检查 x-objectstack-signature)、流式响应(已声明的端点只返回一个 JSON 信封),以及平台不支持的协议。

import type { ApiEndpoint } from '@objectstack/spec/api';

// The stack declares `manifest: { namespace: 'acme', … }` — required, see below.
export const leadFeed: ApiEndpoint = {
  name: 'acme_lead_feed',
  path: '/api/v1/apps/acme/leads',      // /api/v1/apps/<namespace>/<subpath>
  method: 'GET',
  summary: 'Lead feed',
  type: 'object_operation',
  objectParams: { object: 'acme_lead', operation: 'find' },
  // `authRequired` omitted → defaults to `true`. Omission is SAFE.
  cacheTtlSeconds: 30,                   // GET-only; rides success answers only
};
路径例外规则(ADR-0121 D1/D2)

已声明的路径必须为 /api/v1/apps/<manifest.namespace>/<subpath>。只有 subpath 可以由你命名,且必须遵循下文的一般命名规则。 必须显式声明 manifest.namespace——绝不会从 manifest.id 派生。发布时,任何超出此路径范围的路径都会被拒绝。

五项发布门禁及对应解决方法

运行时无法提供服务的声明会在发布时被拒绝,一次检查一道门禁。不要死记门禁文本;请阅读拒绝信息,其中包含 修复方法。五项门禁:命名空间(见上文的路径例外规则)、受支持的目标 (script / proxy 在 17.x 中不会执行;object_operation 需要同时设置 objectParams.object 和 .operation;flow 需要 target)、映射(见下文)、策略(见下文)和唯一性(每个栈只能声明一项 METHOD + 路径)。

authRequired 和 D6 配对要求

authRequired 默认为 true,因此省略此项是安全的。只有显式设为 false,才会开放匿名、未经身份验证的执行入口——而 ADR-0121 的 D6 要求同时配置一个已启用的预算:

authRequired: false,
rateLimit: { enabled: true, windowMs: 60_000, maxRequests: 100 },

门禁检查的条件是 rateLimit.enabled === true,而不是是否存在该键: RateLimitConfigSchema.enabled 本身默认为 false,因此只填写 windowMs / maxRequests 只会声明一个不会计量任何请求的预算。端点预算的计量独立于服务器级别的 server.security.rateLimit。

映射键:仅用于投影

inputMapping / outputMapping 只能按点路径移动和重命名字段,不能做其他操作。inputMapping 映射请求正文,在策略链之后、委派之前应用(因此映射绝不能让调用方绕过 authRequired 或速率限制);outputMapping 仅应用于成功响应正文。编写映射前,有三点需要了解:

  • transform 会被拒绝——不存在转换函数注册表。请在值生成的位置计算该值(工作流或公式字段)。
  • find / get / delete 类型的 object_operation 不会读取请求正文,因此其 inputMapping 会被拒绝。
  • 两个条目不能写入相同的目标路径,也不能一个路径位于另一个路径之内 (x 和 x.y)。
升级低于 17 的技术栈

面向旧版主版本编写的 apis: 块,即使一个字节都不改,含义也会发生变化——原本不起作用的文档会变成执行入口。升级前,请先完成协议升级指南中的 declarative-apis-endpoints-live 部分;这是一项安全审查,而不是重命名。两个关键步骤:将每个 path 移入 carve-out,并搜索每个条目中的 authRequired: false。


端点命名约定

模式用例示例
/api/v1/data/{object}自动生成的集合/api/v1/data/accounts
/api/v1/data/{object}/:id自动生成的记录/api/v1/data/accounts/abc123
/api/v1/{object}/:id/{action}对记录执行自定义操作/api/v1/cases/:id/close
/api/v1/{domain}/{action}域级操作/api/v1/ai/chat
/api/v1/apps/{namespace}/{subpath}声明式 apis: 端点——carve-out,不是任意选择/api/v1/apps/acme/leads

规则:

  • 集合路径始终使用复数名词(accounts,而非 account)。
  • 多词路径使用 snake_case(project_tasks,而非 projectTasks)。
  • 动词仅用于操作,不用于 CRUD(/close、/approve)。
  • 始终添加 /api/v1/ 前缀以标明版本。

API 方法(操作)

可编写的 ApiMethod 枚举就是六种基本操作。范围更广的 EFFECTIVE 词汇(ApiOperation,14 个值)是权限门控和响应所使用的词汇;其中额外的八个动词绝不会在 apiMethods 中声明:

可编写的基本操作:

方法当前 HTTP 接口用途
getGET /data/{object}/:id获取单条记录
listGET /data/{object}按筛选条件、排序和分页列出记录
createPOST /data/{object}创建新记录
updatePATCH /data/{object}/:id更新现有记录
deleteDELETE /data/{object}/:id删除记录
bulkPOST /data/{object}/batch批量创建/更新/删除(bulk ∧ 子操作)

派生操作(自动授权,从不手动编写):

操作派生自当前 HTTP 接口
upsertcreate ∧ update不生成接口
aggregatelistPOST /data/{object}/query,带有 groupBy/aggregations
searchlist ∧ searchable全局 GET /api/v1/search,不是针对单个对象
importcreate ∨ update(精确遵循 writeMode)POST /data/{object}/import
exportlistGET /data/{object}/export

history(由 get ∧ trackHistory 派生)仅用于权限门控。restore/purge 不会派生——回收站接口已弃用。在 apiMethods 中声明任何派生动词,都会在解析时被剥除,并显示 FROM → TO 警告。


发现与健康状态

GET /api/v1/health、GET /ready(运行时返回 200/启动中返回 503)和 GET /api/v1/discovery(每个服务的状态)在每次部署中都存在。三者都是响应接口——无需编写。


分发器错误代码

HttpDispatcher 是中央请求路由器;它会返回:

HTTP 状态错误代码发生时机
404ROUTE_NOT_FOUND没有路径匹配的路由
405METHOD_NOT_ALLOWED路由存在,但不支持该方法
501NOT_IMPLEMENTED路由已声明,但处理程序仍是存根
503SERVICE_UNAVAILABLE服务已注册,但尚未就绪

实时订阅

实时契约采用指针式引用;具体结构请查看规范源码:

  • node_modules/@objectstack/spec/src/api/realtime.zod.ts — TransportProtocol (websocket | sse | polling)、SubscriptionSchema(id、events[]、 transport、可选的 channel)、RealtimeEventSchema 和 RealtimeConfigSchema。
  • node_modules/@objectstack/spec/src/api/websocket.zod.ts — WebSocket 消息协议:订阅/取消订阅消息、事件传递、presence、光标和协同编辑消息,以及 ack/error/ping/pong 帧。

身份验证与授权

RBAC(definePermissionSet)和 RLS 属于 objectstack-data 的范畴,不属于此处;本节介绍端点自身的身份验证键。

身份验证配置

端点没有嵌套的 auth 块,也没有 name / request / response 字段:身份验证由 RestApiEndpointSchema 上的扁平 public + permissions 键值对表示;声明式 ApiEndpointSchema 端点(以及 dispatcher)使用 authRequired: boolean(默认为 true)——将其设为 false 时,必须配置 rateLimit(ADR-0121 D6 — 请参阅上文声明式端点 → authRequired 与 D6 配对规则)。速率限制策略由 RateLimitConfigSchema 定义:

import { RateLimitConfigSchema, type RateLimitConfig } from '@objectstack/spec/shared';

const limit: RateLimitConfig = RateLimitConfigSchema.parse({
  enabled: true,
  windowMs: 60_000,     // time window in milliseconds
  maxRequests: 100,     // max requests per window
});
身份验证提供方

提供方和登录契约位于 node_modules/@objectstack/spec/src/api/auth.zod.ts:AuthProvider 为 'local' | 'google' | 'github' | 'microsoft' | 'ldap' | 'saml',而 LoginRequestSchema 包含 type(登录方式),以及可选的 email、 username、password、provider 和 redirectTo。接入身份验证流程前,请先查看该文件,了解会话和令牌响应的结构。


数据源

defineDatasource、schemaMode、external 写入门控和 credentialsRef 位于 objectstack-data → rules/datasources.md;驱动程序包以及 Turso Cloud/EE 注意事项位于 objectstack-platform → 驱动程序选择指南;driver ID 的词汇表位于 data/driver/config-registry.zod.ts。


错误封装与代码台账(ADR-0112)

error.code 分为两层:封闭的 StandardErrorCode 目录,以及在各所属包的 api/error-code-ledger.zod.ts 中注册的代码。 ApiErrorSchema.code 会校验这两类代码的并集,因此,未注册的代码会导致解析失败 → 封装一致性测试套件失败 → CI 失败。

该台账只收录框架包。下游仓库应保留自己的台账,并自行组合两项检查——envelopeViolations(body) 用于检查结构,makeApiErrorSchema(yourCodes) 用于检查词汇表(两者均位于 api/contract.zod.ts)。任何仓库都不得发出完全未在任何台账中登记的代码。


最佳实践

  1. 尽可能使用自动生成的 API。 只有在业务逻辑无法通过 CRUD + 触发器实现时,才创建自定义端点。
  2. 返回一致的错误结构。 dispatcher 封装为 DispatcherErrorResponseSchema:{ success: false, error: { code, message, httpStatus?, route?, service?, hint? } },其中 code 是语义字符串,且必须包含 code 和 message。通用 API 错误使用 ErrorResponseSchema(errors.zod.ts)。请注意,已发布的数据路由返回的是扁平的 { error, code } 响应体(例如,CONCURRENT_UPDATE → 409,VALIDATION_FAILED → 400)——不要假定每个错误都会使用 success: false 封装。
  3. 采用最小权限身份验证。 每个端点都应明确声明所需权限。
  4. 有意设计幂等写入。 系统不会生成 upsert 路由,因此外部集成需要按其唯一外部 ID 查询,并分支执行创建或更新——通过 POST /api/v1/data/{object}/batch 对这些写入进行分组。

常见陷阱

  1. 未处理 409 Conflict。 生成的 PATCH /api/v1/data/{object}/:id 路由通过两种写法实现乐观并发控制:If-Match 标头 或 JSON 请求体中的 expectedVersion 字段——如果两者都发送,以请求体为准,且令牌通常是客户端读取的 updated_at 值。两者都不发送会跳过检查;版本不匹配时会返回 409 CONCURRENT_UPDATE;带引号的空实体标签("")会被拒绝,并返回 400 VALIDATION_FAILED,而不是被视为未提供。
  2. 认为 DELETE 可以恢复。 ObjectStack 的 DELETE 是硬删除——没有回收站(已废弃的 enable.trash 标志已在 16.x 中移除)。如需支持恢复,请使用针对每个字段的 trackHistory(审计跟踪)或 lifecycle 归档策略,而不是自定义软删除逻辑。

验证你的工作

添加 *.endpoint.ts、自定义路由或身份验证提供程序后,在报告完成之前运行作者时检查:

os validate     # Zod schema + CEL predicate validation + bindings (no artifact)
# or: os build  # the same gates, plus emits dist/

路由守卫和身份验证谓词使用 CEL;检查会解析这些谓词,并在出错时以非零状态退出,同时指出错误位置,而不是让格式错误的守卫在运行时被忽略。在脚手架生成的项目中,该检查命令为 npm run validate。完整的检查列表请参见 objectstack-platform → 验证你的工作。


参考

完整的 Zod schema 列表(含单行说明)请参见 references/_index.md——其中列出了 node_modules/@objectstack/spec/src/ 中的对应内容。要确认确切的字段结构,请始终Read源代码;不要依赖对属性名称的记忆。

评论

支持 Markdown