Pageable 协议设计规范
设计背景与目标
在TFRobotServer中,所有的RobotComponent均是通过配置生成,数据结构多变,分页列表的字段、操作、联动方式都可能变化。平台内核通过Action机制,结合JsonSchema、Jmespath、x-namespace/x-actions/x-ref,实现了列表(pageable)场景的协议规范。
基本约定
- 所有列表相关Action需通过@tfs_action注册,category为"pageable"。
- 每个Action需定义清晰的入参Schema和返回Schema,均基于Pydantic/JsonSchema表达。
- 支持通过x-namespace/x-actions/x-ref机制实现接口间联动。
典型接口结构
1. 主列表查询Action(get_list)
- get_list 的返回结构必须为“列表容器”,最小要求是包含 items 字段。
- 分页信息根据分页模式不同可选:
- Page 模式:items + page + pageSize
- Cursor 模式:items + cursor + pageSize
- 返回Schema可在 items 的每个元素结构中声明 x-namespace,为所有Action提供变量。x-namespace 直接以变量名为 key,value 为 Jmespath 路径或 Options 结构(labels/keys/values 三个 Jmespath 字段,见下方示例)。
- 可在每个元素结构中声明 x-actions,表明当前行可用的操作。
- x-namespace 的 key 为变量名,value 为 Jmespath 路径或 Options 结构。
{
"type": "object",
"properties": {
"items": {
"type": "array",
"items": {
"type": "object",
"properties": {
"id": {"type": "string"},
"name": {"type": "string"}
},
"required": ["id", "name"],
"x-namespace": {
"row_id": "id",
"user_options": {
"Options": {
"labels": "values[*].display_name",
"keys": "values[*].user_id",
"values": "users"
}
}
},
"x-actions": ["update_row", "delete_row", "select_user"]
}
},
"page": {"type": "integer"},
"pageSize": {"type": "integer"}
},
"required": ["items", "page", "pageSize"]
}
Cursor 模式示例(返回结构):
{
"type": "object",
"properties": {
"items": {"type": "array", "items": {"type": "object"}},
"cursor": {"type": "string"},
"pageSize": {"type": "integer"}
},
"required": ["items", "cursor", "pageSize"]
}
2. 行操作Action(如update/delete/select_user)
- 入参Schema字段可通过 x-ref 声明依赖,直接引用 namespace 中的变量名。
- 可通过 x-default 声明字段默认值,值为 Jmespath 路径(相对于当前 namespace)。
- 可通过 x-fetch 声明“补全动作”,当 x-ref/x-default 无法从当前 namespace 解析出值时,前端可触发该动作补全 namespace,然后重试解析。
{
"type": "object",
"properties": {
"row_id": {
"type": "string",
"x-ref": "row_id"
},
"user_id": {
"type": "string",
"x-default": "user_options.keys[0]",
"x-fetch": "aget_user_options"
},
"new_value": {"type": "string"}
},
"required": ["row_id", "user_id", "new_value"]
}
x-fetch 前端实现要求(列表场景)
- 触发条件:仅当
x-ref/x-default均无法从当前 namespace 得到可用值时,才允许触发x-fetch。 - 缓存/去重:前端必须按
(action_name + resolved_params)维度对x-fetch做缓存/去重,避免重复触发相同补全动作。 - 循环/风暴控制:同一次参数解析链路中,
x-fetch最大触发次数为10;超过阈值应中止并提示。
x-namespace/x-actions/x-ref 与 List 的最佳实践
- 推荐在 items 的每个元素 schema 层级声明 x-namespace 和 x-actions,x-namespace 以变量名为 key,所有 Action 共享同一 namespace,便于统一引用。
- x-ref 直接引用变量名,前端自动匹配当前上下文。
- x-default 支持字段默认值从 namespace 动态获取。
- x-fetch 仅填写动作名称字符串,用于在 x-ref/x-default 解析失败时补全 namespace。
- Jmespath 用于表达相对路径,如 "id"、"person.name"。
FAQ
- Q:能否只在根节点声明所有 x-namespace?
- A:不推荐。建议在 items 层级声明,便于每个数据项独立注入上下文。
- Q:如何表达 list 中“对应 index”?
- A:前端遍历时自动注入当前项的 namespace,x-ref 直接写变量名即可。
- Q:x-namespace 的 Options 结构是如何使用的?
- A:Options 结构用于注入选项型变量,labels/keys/values 三个 Jmespath 字段分别对应选项的标签、键和值。
示例
- get_list返回:
{
"items": [
{"id": "1", "name": "A"},
{"id": "2", "name": "B"}
],
"page": 1,
"pageSize": 10
}
- update_row参数:
{
"row_id": "1",
"new_value": "A1"
}
- select_user参数:
{
"user_options": {
"Options": {
"labels": ["用户1", "用户2"],
"keys": ["1", "2"],
"values": ["用户1", "用户2"]
}
}
}
联动与上下文
- 前端根据x-ref自动推导参数来源,实现Action间数据流转。
- 后端在Action注册与Schema中声明所有依赖,便于前端理解与渲染。
扩展与约定
- 支持x-ui、x-table-column等扩展字段,提升前端体验。
- 支持多级联动、复杂表格等高级场景。