搞了十几年系统设计,天天跟接口打交道,我最大的体会是:接口是系统的“契约”,不是“实现”。把这句话想透了,一半的坑你都能绕开。剩下那一半,基本就在下面这 36 个锦囊里。
这里说的“接口”,往大了讲可以涵盖软件 API、硬件引脚、通信协议,无论哪种形态,核心诉求都一样:让调用方不关心内部细节,让实现方不被外部绑死,让双方基于一份稳定的“约定”协作。所以这篇文章虽然主要讲 API 设计,但涉及的思路,像接口定义、接口封装、接口幂等性、兼容性处理、压力测试这类话题,对嵌入式接口、硬件接口设计同样有参考价值。
全文 36 个锦囊,我按 5 个层面拆开讲:资源规划与命名、参数版本与数据呈现、状态码与错误处理、安全幂等与性能、封装文档与契约,最后再补一套配套落地的接口自动化和压力测试经验。适合后端、前端、测试、架构师,以及所有需要写接口、调接口、维护接口的人。
1. 先把思路理清:接口设计到底在解决什么问题
1.1 接口定义决定了协作边界
很多人以为接口设计就是“把 URL 起个名、返回一段 JSON”,其实接口定义的真正价值是划定协作边界。边界划得好,前端和后端可以并行开发,各团队之间互不阻塞;边界划得差,吵架、返工、熬夜联调都是家常便饭。
我见过最典型的一个场景:后端把数据库表字段直接返回给前端,连字段名都没改,比如 user_info.user_phone_number。前端为了展示一个手机号,得先处理各种 null、空字符串、历史脏数据。一旦业务表改名,后端直接把整个接口调挂。这就是没有边界意识,让实现细节泄露到了外部。
好的接口定义,本质上是把“内部怎么存、怎么算、怎么组织”和“外部怎么用、能看到什么”彻底分开。调用方只依赖接口契约,不依赖实现逻辑。这样系统才能横向扩展、纵向演进。
1.2 接口设计要同时服务三类人
做接口设计,你需要同时照顾三类人:直接调用你接口的开发者、运营和监控系统的运维人员、以及未来接手维护的“三个月后的自己”。
开发者关心的是好不好懂、好不好调、报错清不清楚。运维关心的是能不能监控、能不能限流、出问题时能不能快速定位。维护者关心的是能不能兼容升级、有没有文档、有没有弃用计划。一套好接口,必须在这三件事之间找到平衡,而不是只满足其中一方。
1.3 软件接口和硬件接口的通用原则
顺便说一句,这个道理放在硬件接口上一样适用。你看 RS422 接口定义、LVDS 接口、GMII 接口时序参数、SFP 接口引脚定义,本质上都是在做一件事:把物理层、链路层的细节固定下来,让不同厂商的设备可以互联。谁要是把引脚定义随便换、时序参数写得含糊,设备之间就直接无法通信。
所以无论是设计 API 路由,还是定义硬件引脚图,原则是一致的:明确、稳定、可验证、可兼容。这也是为什么我把“接口定义”放在所有锦囊之前,没有清晰的定义,后面全是无源之水。
需要模型API调用? 免费领10W Token,多模型网关一键接入 Claude、DeepSeek 等主流模型。
2. 资源规划与命名:8 个锦囊打好地基
2.1 资源设计与 URL 规则:前 4 个锦囊
锦囊 1:用名词表示资源,不用动词
URL 里出现动词,基本等于告诉别人“你还没想清楚资源的本质”。POST /createOrder 这种写法会让接口语义越散越多,维护到最后就是一场灾难。正确做法是:
code复制POST /api/v1/orders
GET /api/v1/orders/123
创建订单的动作,交给 HTTP 方法去表达;URL 只表示“订单”这个资源。
锦囊 2:集合用复数,保持一致性
/api/v1/users 和 /api/v1/users/123 比 /api/v1/user/123 更一致。复数表达集合,单数表达单体,这套规则虽然简单,但能显著降低理解成本。最怕一个项目里既有 /user 又有 /orders,混乱到连内部人都要翻文档。
锦囊 3:嵌套层级控制在 2 层以内
比如查询某个用户的订单:GET /api/v1/users/{userId}/orders,这种层级没问题。但如果写到 /api/v1/users/{userId}/orders/{orderId}/items/{itemId}/comments/{commentId},说明你已经过度嵌套了。层级越深,接口越脆,缓存和权限控制都难做。遇到多层嵌套,建议把子资源单独抽出来:GET /api/v1/order-items/{itemId},或者用查询参数表达归属关系。
锦囊 4:URL 参数不要用不直观的缩写
我见过有人用 /usr/info 代表用户信息,用 /ord/detail 代表订单详情。缩写一旦失去“直觉”,就是在给调用方制造记忆负担。代码里你当然可以用简称,但对外暴露的 URL 要尽量用全称和约定俗成的叫法。
2.2 命名惯用与层级控制:后 4 个锦囊
**锦囊
