mcpField
O
old-coder-api

old-coder-api

github.com/amazingang开发75397 次安装10 周前更新
代码仓库

关于 old-coder-api

old-coder-api 是供 Agent 设计或审查 HTTP/JSON API 的技能,提供兼容性、授权、重试、分页和运行风险检查,并规定审查结果格式。

主要功能

  1. 01HTTP/JSON 契约设计指引
  2. 02现有 API 兼容性检查
  3. 03身份验证与授权关卡
  4. 04幂等性与分页指引
  5. 05API 审查结果格式

适用场景

  1. 01设计新的 HTTP/JSON API
  2. 02检查改动是否破坏兼容性
  3. 03审查访问控制与重试安全
  4. 04评估速率限制和大型集合

安装

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

$npx skills add https://github.com/amazingang/old-coder --skill old-coder-api

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

包含的文件

除 SKILL.md 外,安装时一起下载的参考资料和脚本。

references/
breaking-changes.md
examples.md
patterns.md

详细介绍

old-coder-api

灵感来自 Sean Goedecke 的文章 Everything I know about good API design(2025-08-24)。

这项技能涵盖 HTTP/JSON 契约和可运维性方面的考量。兼容性规则以 JSON 消费方为前提。对于 gRPC/protobuf、GraphQL、WebSockets 或其他协议,只有结合相应协议自身的兼容性规则,才能应用与传输方式无关的原则。它不能替代完整的应用安全审查。

好的 API 枯燥乏味。 对构建 API 的人来说,API 是一种产品;对使用 API 的人来说,它只不过是实现其他目标途中用到的一件工具。消费者花在琢磨你的 API、而非专注于自身目标上的每一分钟,都是浪费。一个有意思的 API 就是糟糕的 API——至少,不那么有意思的话会更好。

Agent 默认容易陷入两种失误,这项技能正是为避免这两者而设:

  1. 凭空设计。 本可使用枯燥、惯常的接口,却另行设计出巧妙而定制的接口。
  2. 破坏兼容性。 因为某个字段现在看起来更好,就重命名、重构或收紧其约束——悄无声息地破坏所有下游调用方。

与 old-coder 配合使用: 当两项技能都适用时,本技能负责 HTTP/JSON 契约,而 old-coder 负责工作流顺序、SPEC 审批、 gauntlet 和 EVIDENCE。请在 SPEC 审批前执行步骤 0 和各项关卡;将 保留的 API 约束和风险写入 SPEC,并通过 gauntlet 进行验证。对于没有实现工作的纯审查,请使用本技能的审查格式,不要凭空制造开发循环。

步骤 0 — 设计前先明确范围

在编写路由前,先明确回答以下三个问题:

问题为什么会影响工作
面向公众还是内部使用? 能否为每个消费者发布代码?内部使用:可以接受破坏性变更,复杂的身份验证也没问题,无需考虑非工程师的易用性。面向公众:上述条件都不成立。
现有接口还是从零开始?现有接口 → 先运行 references/breaking-changes.md;兼容性优先于下文的所有改进。
产品的资源模型是否支持此 API?API 设计应围绕产品的基本资源展开。如果资源模型很别扭(没有名称的状态机、仅存在于某个作业中的记录、未建模的父子关系),无论设计得多么谨慎,API 都会很别扭。请直言不讳,不要试图掩盖问题。

步骤 0 的诚实原则: 如果问题的根源在于底层模型,就应明确指出,并提出修正模型作为真正的解决方案。对本应直接读取的内容,硬套一个后台作业轮询接口,正是最糟糕 API 的成因之一——被 UI 隐藏的技术约束会在 API 中暴露无遗,迫使消费者理解远超其本该了解的系统细节。

各项关卡

逐一执行所有关卡。只有经过验证并通过时才使用 ✓;经过验证并确认失败时使用 ✗ + 具体修复方案;只有在关卡确实不适用时才使用 N/A + 原因;尚未验证时使用 ? + 原因。绝不能悄悄跳过。

1. 平淡易懂

合格的使用者应该无需阅读任何文档,就能猜到这个端点。

  • 资源使用产品中的名词(/issues、/projects、/users),采用复数形式且保持稳定。
  • 使用标准动词和状态码,并遵循此 API 已确立的惯例。一般客户端错误使用 400;只有在内容类型和语法均有效,但其中包含的指令无法处理时,才使用 422。资源不存在时使用 404,请求受限时使用 429。
  • 使用标准字段名:id、created_at、next_page、url。与此 API 其余部分已使用的名称保持一致——发生冲突时,内部一致性优先于外部惯例。
  • 除非另有理由,否则使用 REST + JSON。成熟且内部一致的 HTTP RPC 接口也可以保持平淡易懂;不要为了追求 REST 的纯粹性而将其改名为资源路径。不要反复争论 HATEOAS 或 JSON 与其他格式之争;这并不重要。
  • 任何出人意料的设计都需要附上一句书面说明。 如果写不出来,就采用平淡易懂的设计。
2. 不要破坏现有用户空间

仅适用于对现有接口的变更。完整对照表见 references/breaking-changes.md。

  • 增量式变更没有问题:新增端点、新增可选参数、新增响应字段。应假设使用方会忽略未知字段。
  • 移除字段、重命名字段、更改字段类型、移动字段(user.address → user.details.address)、缩小枚举范围或收紧验证规则,都是破坏性变更。不要这样做,即使这样更整洁也不行。HTTP referer 标头的拼写有误,但它仍然存在。
  • 如果确实无法避免破坏性变更:版本控制是最后的手段——参见参考文档。
3. 身份验证:让最简单的安全路径变得容易

许多服务器到服务器集成最初只是一个 curl 命令或一段 20 行的脚本。对于面向开发者的服务器到服务器 API,默认使用简单、权限范围明确且可撤销的 API 密钥。

  • 对于浏览器/移动客户端、用户委托访问、高敏感性数据,或策略要求的环境,应改用 OAuth 或其他短时有效或发送方约束的流程。不要向这些客户端发放长期有效的持有者凭据。
  • 对于每种凭据类型,都要定义权限范围、轮换、撤销、安全传输方式,以及在发生安全事件时识别或停用凭据的方法。
  • 对于内部凭据管理,不适用此要求:使用基础设施已有的机制(mTLS、工作负载身份、服务令牌),同时仍须验证其运维控制措施。
4. 授权:强制执行谁可以对哪个资源执行什么操作

身份验证用于识别调用方;它并不授权操作。对于每个端点,都要明确参与者、操作、资源和租户边界。

  • 在服务端对已解析的资源执行授权检查。未经核验,不要信任调用方提供的 tenant_id、所有者 ID、角色或权限范围。
  • 对列表、搜索、批量操作、导出、嵌套资源和间接查找路径应用相同的检查;获取数据后再过滤并不能构成授权边界。
  • 仅当操作有意设为匿名公开时才不适用,并用一句话说明理由。对于安全敏感的变更,除这些 API 审核门槛外,还必须进行专门的安全评审。
5. 对所有会产生实际操作的请求实现幂等性

500 错误或超时并不能告诉调用方操作是否已执行。如果没有幂等键,调用方只能在操作丢失和重复操作之间做选择。

  • 对所有尚不具备幂等性、且会创建内容、触发操作或应用相对变更的操作,都应接受幂等键(请求头或参数);重复使用同一密钥时,应返回原结果,而不是再次执行操作。
  • 对低风险操作,可将幂等键设为可选,因为偶尔重复操作的代价低于增加接入阻力。
  • 如果重复操作不可接受——例如支付、转账、用药、不可逆的外部副作用——则必须要求幂等键或内在唯一的操作 ID,并在执行操作时以原子方式进行去重。
  • 读取操作(无害)不需要;DELETE /comments/32 也不需要(ID 本身就是密钥,重试只会返回 404)。例外:不以 ID 为范围的操作,例如“删除最近的一条”。
  • 存储方案见 references/patterns.md。
6. 影响范围、速率限制、紧急开关

UI 用户的操作速度受限于手速。通过 API 暴露的任何功能,都会被代码以代码的速度调用,永不停歇地循环调用,调用者可能根本没读过文档。

  • 发布前:写下单个调用方在紧密的 while true 循环中会给你带来多少成本。扇出请求、/index 端点、批量导入,以及请求中按记录逐项处理的操作都很危险。
  • 对所有操作实施速率限制,对开销大的操作设置更严格的限制。
  • 返回 X-RateLimit-Remaining 和 Retry-After,让遵守规则的客户端能够降低请求频率——正是这些元数据,让你可以设置比原本更严格的限制。
  • 为每个使用方保留一个紧急开关。你迟早会在一次由意想不到的集成引发的事件中用到它。
7. 分页
  • 任何可能增长到很大的集合:始终采用基于游标的分页。WHERE id > :cursor ORDER BY id LIMIT :n 在记录数达到一百万时依然很快;OFFSET 会随着每一页而变慢,之后再迁移的成本也很高。
  • 永远有界的集合(用户的 API 密钥、项目的 5 个环境):使用页码或偏移量均可。
  • 切勿返回无界列表。始终包含 next_page(URL 或游标),避免使用方自行计算。
8. 开销大的字段应为可选项,且默认关闭

如果某个字段需要额外的服务调用、对大表进行联接,或执行计算,就不要将它放在默认响应中。

  • 通过 ?include=subscription / includes[] 数组控制是否返回该字段;保持默认响应开销低且成本恒定。
  • 这是 GraphQL 思路中实用的 20%,却不必承担其成本。
  • 除非用户提出要求,或代码库已经在使用 GraphQL,否则不要提议采用 GraphQL:非工程师的使用门槛高;由客户端任意构造的查询会使缓存更复杂,并增加边缘情况;后端也更难处理。它是最后的选择,而不是默认方案。
9. 不要泄露实现细节

站在陌生人的角度阅读响应。要正确使用它,是否必须知道你的存储方式?

  • 泄露示例:要求客户端逐个遍历的 next_comment_id 链;本该使用 GET 的操作,却采用 POST /fetch_job 加轮询的流程;内部枚举值;内部表 ID;页大小取决于分片布局的分页方式。
  • 要么用简单的接口隐藏这些细节,要么在 PR 中明确说明相关技术债——不要让它悄无声息地进入公开契约。

刻意不设为门槛

既要防止设计不足,也要同样警惕过度设计:

  • 不要一开始就构建版本管理机制。 /v1/ 前缀本身就是一项面向公众的产品选择,并非免费的占位符。只有当产品的兼容性策略有此要求时,才采用路径或标头版本控制;在第二个版本出现之前,不要构建多版本协商机制。
  • 对于只有一个调用方且结果集有界的内部端点,不要添加 includes 或游标。 分页和高开销字段门槛针对的可能是规模大或成本高的响应。对于幂等性,调用方数量并不能消除重试风险:只有在操作本身已具备幂等性,或明确接受重复效果时,才可以省略。
  • 不要为了让 API 更漂亮而重写能正常工作的 API。 美观不值得以破坏兼容性为代价,也不值得耗费审查时间。
  • 请记住,API 质量的影响有限。 如果产品有价值,即便 API 糟糕,人们也会集成它(Facebook、Jira)。如果产品没有价值,再漂亮的 API 也救不了它。API 质量决定的是两个大致同等产品之间的取舍;真正的问题是完全没有 API。因此:应用这些门槛,不要过度雕琢。

审查输出格式

审查而非编写时,只报告通过核实的问题,不要纠结个人偏好。对于仓库代码、规范和差异,请注明 file:line。对于仓库之外已发布的契约,请注明稳定 URL 和确切章节;代码证据必须使用不可变的提交永久链接,而非会变动的分支。如果缺少公开保证,意味着消费者无法依赖该行为;这并不能证明后端没有未公开的实现。只有审查证据支持时,才将门槛标记为 ✓。有仓库上下文时,应检查差异之外的内容,而不是把沉默视为通过。如果输入有意受限且无法获得更多证据,请使用 ? (unverified: <reason>);仅当某个门槛确实不适用时,才使用 N/A。门槛汇总评估的是正在审查的内容,而非提出修复建议后可能达到的状态。排序:先列破坏性问题,其次是安全边界,然后是事故风险,最后是易用性。

## API review: <surface>
Scope: public|internal · greenfield|existing

### Breaking changes (blocking)
- <field/endpoint> — <what breaks for a consumer doing X> — file:line
  Fix: <additive alternative>

### Security boundary
- <authentication/authorization finding> — <credential or unauthorized action/resource> — file:line

### Incident risk
- <idempotency/blast-radius finding> — <the loop or retry that hurts> — file:line

### Ergonomics
- <boring/pagination/field-cost/implementation-leak finding> — file:line

### Gates: Boring <status> · Compatibility <status> · Authentication <status> · Authorization <status> · Idempotency <status> · Blast radius <status> · Pagination <status> · Expensive fields <status> · No implementation leakage <status>

如果没有任何问题通过核实,请直截了当地说明——空的审查结果也是有效结果。

参考资料

  • references/breaking-changes.md — 兼容性矩阵、版本管理指南、弃用流程。更改任何现有端点前请先阅读。
  • references/patterns.md — 实现方案:幂等键、游标分页、速率限制标头、includes。
  • references/examples.md — 三个简洁的本地示例:现有路由/规范差异、新项目提案,以及已建立的 HTTP RPC 路由。仅在需要具体校准示例时阅读。

评论

支持 Markdown