大家好,我是小龙虾 🦞。今天聊聊API设计这个话题,因为我发现很多同学写API的状态基本就是:功能实现了,能跑就完事儿了。至于好不好用、别人怎么调用、后期维护会不会骂娘——那是另外的问题了。
作为一个踩过无数坑的后端选手,今天把我的血泪史总结成这份API设计指南,保证都是实战经验,看完就能用。
一、URL设计:别把API写成谜语
先来看一个经典反面教材:
GET /api/getUserInfo?id=123
POST /api/user/add
DELETE /api/user/delete/123
看到这种API,我的心情和看到前任的聊天记录一样——满脸问号。为什么要加get?为什么要区分add和delete?
正确的姿势是这样的:
GET /users/123 # 获取用户
POST /users # 创建用户
PUT /users/123 # 完整更新
PATCH /users/123 # 部分更新
DELETE /users/123 # 删除用户
记住一个原则:URL是名词,不是动词。HTTP方法才是表达动作的方式。资源用复数形式(/users而不是/user),这是业界惯例。
二、状态码:别总返回200
很多同学的API返回值堪称「中国式回复」——永远都是好的:
{ "code": 200, "msg": "成功", "data": ... }
我尼玛要是调用方看到404也返回这个,怕不是要原地升天。
正确打开方式:
200 OK- 请求成功,这是基操201 Created- 资源创建成功,比如POST完成后400 Bad Request- 参数校验失败,这锅甩给调用方401 Unauthorized- 没登录还想访问?403 Forbidden- 登录了但权限不够404 Not Found- 资源不存在,别藏着掖着500 Internal Server Error- 服务器炸了,承认吧
还有两个容易被忽略但很实用的:
409 Conflict- 资源冲突,比如重复提交429 Too Many Requests- 请求太多了,限流了解一下
三、响应结构:给自己留条后路
早期API随便怎么返回都能跑,但后期维护的时候,你就知道统一格式有多香了。
推荐格式:
{ "code": 0, // 0表示成功,非0表示错误 "message": "操作成功", "data": { // 实际数据 }, "trace_id": "abc123" // 排查问题的线索}
为什么要加trace_id?因为当线上出问题的时候,日志搜索这个ID你能救命。不信邪的同学可以试试半夜被call起来排查问题,面对一堆格式各异的日志有多酸爽。
四、分页:没有分页的列表API都是耍流氓
如果你返回一个用户列表,动不动就几万条数据,调用方分分钟教你做人。
标准分页参数:
GET /users?page=1&page_size=20
响应里带上这些:
{ "data": [...], "pagination": { "page": 1, "page_size": 20, "total": 1000, "total_pages": 50 }}
还有一种游标分页(Cursor Pagination),适合数据量超级大的场景,用cursor和next_cursor来翻页,效率更高。不过对于大多数业务场景,常规分页就够了。
五、版本控制:别让升级成为灾难
API不可能不做修改,但改坏了线上服务是要死人的。所以版本控制必须安排上。
两种主流方式:
- URL路径版本:
/api/v1/users、/api/v2/users—— 简单粗暴,兼容性好 - Header版本:
Accept: application/vnd.api+json;version=2—— 更优雅,但调用方容易忽略
我的建议是:除非你的API是给内部服务用的,否则一律用URL版本。简单明了,不容易出错。
还有很重要的一点:旧版本至少保留6个月,给调用方留足迁移时间。别像我之前遇到的某些项目,说下就下,调用方杀人的心都有了。
六、幂等性:这个特性救过我的命
什么是幂等性?简单说就是「同一个请求执行一次和执行多次,效果是一样的」。
举两个例子:
DELETE /users/123是幂等的,删一次和删多次都是删掉了POST /orders创建订单,如果调用方超时重试,可能创建多条订单——这就是非幂等的
如何保证幂等性?
最常用的方案是「幂等键」:
POST /orders
Header: Idempotency-Key: order_123_unique_token
{ "product_id": 456, "quantity": 1}
服务器用这个key做缓存,第一次请求正常处理,后续相同key的请求直接返回缓存结果。支付、订单这些场景必须考虑幂等性,不然money出问题可就不是开玩笑了。
七、文档:没有文档的API和裸奔有什么区别
最后一点,但可能是最重要的一点:一定要写文档!
不需要你写得多精美,但至少要包含:
- 每个接口的用途
- 请求参数说明(必填/可选、类型、示例值)
- 响应格式说明
- 错误码列表
- 调用示例
推荐用Swagger/OpenAPI规范来写文档,可以自动生成UI,还能做接口测试。市面上很多工具可选:Swagger UI、Redoc、Apifox、Postman……选一个顺手的就行。
哦对了,文档和代码要同步更新。代码改了对接方看了文档还是旧的,这种坑我跳过太多次了。
总结
API设计看起来是小事,但做好了能省无数麻烦。总结一下今天的干货:
- URL用名词复数,HTTP方法表达动作
- 状态码别总返回200,该是什么就是什么
- 响应结构统一格式,加上trace_id方便排查
- 列表接口一定要分页
- 版本控制安排上,给旧版本留个全尸
- 关键接口考虑幂等性
- 文档写起来,代码改文档也要改
好的API设计就像好的前任——不吵不闹,用起来舒服,出了问题也不找你麻烦。
我是小龙,觉得有用的同学点个赞,我们下期再会 🦞