jwb-api-review · git:20260915.c01fcc9 · 2026-09-15 · sha256 510a3a80d7b2b618
jwb-api-review git:20260915.c01fcc9A
Immutable. This exact content never changes and is served at /api/v1/blob/510a3a80d7b2b618.
--- name: jwb-api-review description: Use when 审查或新增求职工作台后端 API 时,需要按本仓库的错误码契约、状态码语义、两段式写入与安全边界逐条核对。English triggers:API review, REST design, error codes, AIP-193, Zalando API guidelines, two-phase write. compatibility: 面向「开发 / 扩展本仓库后端」的场景;仓库在侧(jobws 指仓库内的 python tools/jobws.py);Python 3.12+。 --- # 后端 API 审查清单 外部参考:Google AIP-193(错误)、AIP-158(分页)、Zalando RESTful API Guidelines。 本文件是本仓库的**落地口径**——与既有代码 / 测试冲突时以测试为准。 ## 错误:加法而非替换 - 每个错误必须同时带 `detail`(人读中文原文)与 `error_code`(稳定语义标识), 用户可见的动态值进 `error_params`; - 命名 `<域>.<语义>`,域与路由对齐(ws / app / status / approval / sys / …); **同一语义跨路由必须复用同一个 code**; - 前端语言包按 code 出一份文案——改 code 等于破坏前端文案,要当契约对待; - 新增 code 必须同步:两个语言包 + 自动校验(判定脚本会扫全部 ApiError 调用, 校验 code ↔ 文案 ↔ 参数三者的对齐)。 ## 状态码语义(本仓库口径) | 码 | 用于 | |---|---| | 400 | 值层面拒绝:未知键、越界的目标、非法路径 | | 404 | 记录 / 工作区不存在 | | 409 | 冲突:预览后数据变了、乐观并发失败(重试前必须重新读取) | | 422 | 语义校验失败(格式、枚举、终态不回退);令牌不可用 | | 200 + ok:false | MCP 工具层的「可读拒绝」形态(宿主不当异常处理) | ## 写入:两段式与安全边界 - 写端点先预览(不落盘)→ 一次性令牌 → apply;「要写什么、写到哪里」在令牌里, **不在请求里**——apply 不接收路径 / 载荷参数; - apply 的落盘段必须持资源锁(「读最新 → 重校验 → 写」整段互斥;锁在领域层的 落盘函数里,不在 web 层单点加——CLI / MCP 走同一条路); - 工作区参数只收相对名,`realpath` 后校验在允许根之内;越界拒绝而非警告; - 路径经安全拼接;错误响应不得泄露未授权位置的信息。 ## 形状与分页 - 资源名用复数、动作由 HTTP 方法承载;响应字段 camelCase;与 CSV 列名对齐的 数据字段保持原样(中文列名不翻,展示层再映射); - 列表响应:`items` + `total`;大集合设上限并提示「另有 N 条」(返回体不随 数据量膨胀); - 时间用 ISO 8601 字符串;「未提供」用 null,不用空字符串表达。 ## 审查动作(逐条走) 1. 列出本 PR 的全部写端点:每个都有预览 + 令牌吗?落盘锁在哪一层? 2. 扫 ApiError 调用:code 是否与既有同义 code 重复定义?参数是否齐全? 3. 扫前端 `err.<code>`:新增 code 两侧语言包都补齐了吗? 4. 路径与工作区边界:有没有绕过既有校验的新入口? 5. 兼容面:默认行为是否不变?破坏性变更是否走了版本流程? ## 常见错误 | 错误 | 后果 | 正确做法 | |---|---|---| | 新错误只给 detail 不给 code | 英文界面露出中文原文 | 同步双语言包 | | 同义错误用了两个 code | 前端文案漂移 | 复用同一个 code | | 写端点直接落盘 | 用户失去确认权 | 两段式 + 令牌 | | 锁只加在 web 层 | CLI / MCP 路径并发丢写 | 落盘函数自持锁 | | 列表接口不设上限 | 大数据撑爆响应 | items 上限 + total |