Skip to content

Latest commit

 

History

History
150 lines (111 loc) · 10.5 KB

api-workbench.md

File metadata and controls

150 lines (111 loc) · 10.5 KB

接口工作台

管理后台的「接口」页把三件原本只能改代码的事拆开,按风险分级:

能力 谁用 改什么 怎么生效 风险
文案编辑 运营 / 管理员 标题、描述、参数说明、示例、返回字段说明 保存即生效,不重启 低:结构字段只读
新增声明式接口 运营 / 管理员 取值 → 请求上游 → 字段映射的 JSON 配置 草稿 → 发布,立即注册路由 中:只能调上游和映射,不执行代码
核心接口实现 研发 src/apis/** 里的 JS 提交 + 更新/重启 高:仍走代码审查

一、两条底线

  1. 代码是结构的唯一权威。 文案覆盖层(api_meta)没有修改参数名、类型、必填、枚举的入口,合并函数只写 title / description / summary / desc / example。覆盖前后的 shapeHash 必须完全相等,test/api-meta.test.js 锁住这一点。
  2. 线上改动要能回滚。 声明式接口每次发布都写一条 custom_api_versions,回滚只切换线上指针,不依赖 git;删除会同时删除发布记录,但会留下操作审计。

二、文案编辑

  • 一行覆盖 = 一个补丁;删掉补丁即恢复代码默认值,不会出现"字段没文档"。
  • 每条补丁记录自己的结构指纹(targetRev)。参数约束或代码结构变了、内容无效时,覆盖立即停止生效,目录恢复代码默认文案;体检标为「待确认」,管理员确认保存后才重新生效。
  • 合并时同时检查目标、结构指纹和内容合法性决定是否生效:代码里已经没有的字段,补丁自动失效并进入「孤儿」清单,可一键清理。
  • 并发:详情和列表返回持久的 editRev,每次写入必须提交 expectedRev;旧页面、其他标签或进程已修改内容时返回409并保留当前输入,不静默覆盖。所有写入与审计在同一事务,文案按目标记录前后值;版本跨重启保留。

体检分类(GET /admin/apis/doctor):

kind 含义 处理
orphan 代码里已没有这个字段 还原或清理补丁
stale 保存后代码结构变过 确认文案是否仍然准确
invalid 超长、必填为空、含控制字符 改短或还原
module-missing 整个接口已被删除 清理补丁
invalid-target 目标格式不合法(旧版本遗留) 清理补丁

三、新增声明式接口

配置存在 custom_apis(草稿 draft 与线上 config 分开),启动和发布时由 registry 合并进路由表,不写入代码目录,因此在线更新不会冲掉。

最小配置:

{
  "name": "custom-example",
  "category": "tools",
  "title": "示例接口",
  "description": "从后台新增的接口",
  "sourceInfo": { "kind": "third-party-service", "network": "required", "summary": "示例数据源" },
  "routes": [{
    "method": "GET",
    "path": "/api/custom/example",
    "summary": "按关键词查询",
    "params": [{ "name": "q", "required": true, "desc": "关键词", "example": "hello", "maxLength": 40 }],
    "url": "https://api.example.com/search?q={q}",
    "extract": "data",
    "map": { "title": "name", "link": "url" },
    "fields": [
      { "name": "title", "type": "string", "desc": "标题" },
      { "name": "link", "type": "string", "desc": "链接" }
    ],
    "cacheTtlSec": 300,
    "timeoutMs": 10000
  }]
}

规则(发布前全部校验):

  • name 3~40 位小写字母/数字/-,不能和核心接口重名;path 以 /api/ 开头,不能带 :。
  • url 里用 {参数名} 取值(自动 URL 编码),{env:CUSTOM_API_变量名} 仅引用显式声明的专用环境变量;不能读取 SMTP、会话或其他系统密钥;必填参数必须给 example(自动检测会用它)。
  • 上游域名和端口必须固定;仅直连公网,DNS 在连接时校验所有解析地址,不跟随任何跳转,不经过系统出站代理。使用专用环境变量的路由必须是 HTTPS。变量被上游反射回传时会隐藏,但仍需信任所配置的上游。
  • 支持 GET / POST;POST 可以给 body(对象或字符串,值同样支持占位符)。
  • extract 从上游响应里取路径(data.items、data.items[0]);取不到时返回 502「上游返回结构可能已变化」,不会静默返回 null。
  • map 把上游字段映射成返回字段;每个输出字段都必须在 fields 里写说明。
  • cacheTtlSec 086400 秒,0 表示实时获取;POST 必须为0。timeoutMs 50020000,覆盖连接和正文;正文最多1 MiB,最多10000个取值节点。
  • 参数支持 string/int、oneOf、长度或数值边界;POST 的 in: "body" 参数从传入 JSON 正文读取。暂不支持自定义正则;禁止 __proto__、constructor、prototype 字段和继承路径。
  • 发布时检查与核心接口(含动态路由)、其他自定义接口的路径冲突;冲突返回 409,不会出现两条路由抢同一个地址。

四、发布与回滚

  1. 在「新建接口」或接口详情的「接口定义」里改 JSON。
  2. 「校验」只做结构与冲突检查,不落库。
  3. 「保存草稿」写 draft,线上不变。
  4. 「发布」要求填写原因(写入操作日志),采用当前编辑器内容;事务内完成保存、验证和 registry 预构建,任一步失败均保留原线上版本,成功后:
    • 版本号 +1,写入 custom_api_versions;
    • registry 重建,新接口立刻出现在 /api 目录、文档页、sitemap、OpenAPI、Key 权限下拉和统计里;
    • 清掉该模块的缓存。
  5. 「回滚到此版」把线上指针切到指定版本;「删除」同时删除发布记录(审计日志保留)。

五、对外契约

  • GET /openapi.json:OpenAPI 3.1,按运行时目录生成,含参数、枚举、示例、x-miao.fields 字段说明。
  • GET /llms.txt:纯文本接口清单,供 LLM/Agent 直接阅读。
  • GET /api:原有目录 JSON,新增模块带 origin: "custom" 和 custom: true。

以上都是运行时生成,后台改文案或新增接口后不需要另写文档;契约响应使用 no-store,避免发布后浏览器继续显示旧目录。

试跑和缓存

本地纯计算可以直接试跑;外部上游、POST 和可能写入本地状态的处理须填写原因并确认,操作留审计。试跑不计调用额度,但可能消耗真实上游配额或产生副作用;不会自动重试。自定义上游始终标记为联网,不参加自动巡检或缓存预热,避免 GET/POST 被后台任务重复调用。已关闭、合规停用或暂停的模块不能绕过状态试跑。

存在已保存草稿时试跑草稿,尚未保存的编辑内容须先保存。试跑绕过线上缓存;缓存按配置、发布代次及专用变量区分,旧请求可以结束但不会污染新版本。

数据库保存、审计和 registry 预构建在同一同步事务;提交后切换快照。其他服务进程在下一次 HTTP 请求前发现版本变化并重建,在途请求继续用旧 route。SQLite 数据必须位于该部署保留的 data/ 目录;不支持跨机器共享内存快照。

六、开发流程与门禁

npm run api:check   # 路径/命名唯一、来源登记、README 数量、接口清单快照
npm run api:sync    # 同步 README 数量和 docs/api-surface.json
npm test

test/api-contract.test.js 和 api:check 共用同一份规则(src/lib/api-contract.js),所以 CI 现有的 node --test 就会拦住过期快照与非法路径,不依赖额外的 workflow 步骤。

新增核心接口时:

  1. 写 src/apis/<分类>/<name>.js(约定见 src/apis/README.md);
  2. 在分类 index.js 里导出;
  3. src/lib/api-sources.js 登记数据来源;
  4. npm run api:sync 更新数量与快照;
  5. 补测试与 fixture。

docs/api-surface.json 是接口清单快照:任何改名、删除或新增都会在 diff 里显示,避免"数量悄悄变了"。

七、边界与后续

  • 本版本不提供在线写任意 JS。声明式配置覆盖"调上游 + 映射字段"这一类需求;需要写解析逻辑的接口仍走代码,理由是可审查、可测试、可回滚。
  • 角色分层(editor 只能改文案、admin 才能发布代码)是下一步,目前工作台只对管理员开放。
  • README 的逐行接口表格仍手写;下一步可以由 docs/api-surface.json 生成,减少一次手改。

八、代码位置

文件 作用
src/lib/api-meta.js 文案补丁:合并、校验、体检、结构指纹
src/lib/custom-api.js 声明式接口:配置校验、运行、草稿/发布/回滚
src/registry.js 可重建的运行时快照(核心 + 文案 + 自定义)
src/routes/api-admin.js 工作台后台接口
src/lib/openapi.js OpenAPI / llms.txt 生成
public/admin-apis.js 工作台页面
scripts/api-check.mjs 契约自检与快照同步

九、隐藏和恢复公开展示

从管理概览 /admin 打开「接口开关与展示」,每张卡片的「公开显示」开关可以立即隐藏或恢复该接口模块(同一模块的多个地址一并处理);上方可按显示/隐藏筛选。接口工作台 /admin/apis 同样保留所有项,详情里可隐藏和恢复,自定义草稿也可预先设置。

隐藏和禁用相互独立:隐藏只移除公开目录、搜索、分类数量、单接口文档、站点地图、OpenAPI/llms、今日推荐和公开状态列表,已有调用地址仍按原来的身份、Key 范围和配额工作。隐藏不能用来保密或阻止调用;停止服务应关闭接口。恢复显示也不会开启已关闭的接口。代码和历史内容中的地址不会被删除。

状态保存在 SQLite module_settings.hidden,旧数据默认为0(显示),刷新及重启保留。保存沿用 expectedRev 和管理员同源 JSON 写入保护,写入与审计原子提交;409或网络失败会保留原开关并提示重新读取后再操作。不重建调用路由或清空当前进程已有调用缓存。自定义接口重新发布/回滚保留隐藏状态;删除后重新创建默认显示。

公开页面导航和快速搜索会重新获取目录;已打开页面仍可能保留之前加载的内容,刷新或再次导航即可更新。隐藏不删除历史统计,平台历史总调用量仍保留。仅编辑已有 API Key 的名称或来源时不重写接口范围,不会因隐藏自动删除或扩大权限;主动调整范围仍按新的勾选结果保存。