为什么你的API总是被人骂?一位老油条的掏心窝子经验
干后端这么多年,我见过太多"能用但不好用"的API。有的返回结构像开盲盒,有的错误信息写着"操作失败请联系管理员",还有的接口名字叫getDataByType2——我也不知道Type1去哪了。
今天不整虚的,就聊聊那些真正让API变好用的东西。有些是我踩过的坑,有些是看到别人踩坑后的反思。看完了要是觉得没用,你来骂我。
一、URL设计:别把API写成迷宫
很多人的API URL是这样的:
GET /api/v1/getUserInfoById?id=123
POST /api/v1/user/query
GET /api/v1/getData
看到这种URL,我血压都高了。URL应该是名词,不是动词。动作交给HTTP方法。
正确姿势:
GET /api/v1/users/123 # 获取用户
PATCH /api/v1/users/123 # 部分更新用户
DELETE /api/v1/users/123 # 删除用户
GET /api/v1/users/123/orders # 获取用户的订单
RESTful不是银弹,但你至少把"获取"和"操作"分清楚。
二、状态码:用对了是专业,用错了是灾难
的状态码管理简直是一言难尽。常见问题:
- 所有成功都返回200,所有失败都返回400
- 明明是服务器挂了,返回个200加个
{"success": false} - 错误信息就三个字:"出错了"
我的建议是,状态码要用准:
200 OK # 成功,且有返回
201 Created # 创建成功,Response Header带Location
204 No Content # 成功,但没返回体(常见于DELETE)
400 Bad Request # 参数校验失败
401 Unauthorized # 没登录
403 Forbidden # 登录了但没权限
404 Not Found # 资源不存在
422 Unprocessable # 格式对但语义错
429 Too Many # 请求过于频繁
500 Internal Error # 服务器挂了
最关键的一点:错误响应必须包含足够的信息让客户端知道发生了什么。
{
"error": {
"code": "VALIDATION_FAILED",
"message": "请求参数校验失败",
"details": [
{"field": "email", "message": "邮箱格式不正确"},
{"field": "age", "message": "年龄必须大于0"}
]
}
}
这种响应,客户端开发者看到会感谢你的。
三、版本管理:不做版本管理的API都是在给自己挖坑
迟早你会遇到要破坏性改动的情况。怎么办?硬着头皮改?然后线上开始报成堆的bug?
版本管理是必经之路。主流方案:
# URL版本号(GitHub、Stripe在用,简单直接)
GET /api/v1/users
GET /api/v2/users
# Header版本号(更"优雅"但不够直观)
GET /api/users
Accept: application/vnd.api+json; version=2
我的建议是URL版本号。为什么?
- 调试方便,直接改URL就能测新版本
- 日志里一目了然
- CDN和网关配置简单
版本什么时候升?当你需要破坏性变更的时候。增删字段不算,字段改名要算。
四、分页:无分页的API都是定时炸弹
你的用户表有一亿条数据,前端请求GET /api/users,你打算返回全部?
轻则超时,重则OOM。
分页是必须的。两种常见方式:
# Offset分页(简单但有性能问题)
GET /api/users?page=1&per_page=20
# Cursor分页(性能好但不能跳页)
GET /api/users?cursor=abc123&per_page=20
大数据量+高频请求,用Cursor分页。普通后台管理界面,Offset够用。
返回结构要统一:
{
"data": [...],
"pagination": {
"total": 1000000,
"per_page": 20,
"current_page": 1,
"total_pages": 50000,
"has_next": true,
"has_prev": false
}
}
五、幂等性:这个概念救过我的命
什么叫幂等?就是执行一次和执行N次,效果一样。
为什么要考虑这个?因为网络会超时、客户端会重试、用户会手抖点两下。
这些操作必须幂等:
- GET - 天然幂等,读一百遍还是那个结果
- DELETE - 删两次和删一次,都是删了
- PUT - 完整替换,幂等
这些操作不幂等(要特别处理):
- POST - 创建资源,重复提交会创建多个
- PATCH - 部分更新,取决于语义
不幂等的操作怎么办?用幂等Key:
POST /api/orders
Idempotency-Key: client-generated-uuid-12345
服务端根据这个Key做去重,重复请求直接返回上次的结果。支付场景必用。
六、文档:没文档的API等于没API
这句话我说一百遍都不嫌多。
你的API再优雅,没人知道怎么用就是白搭。文档要包括:
- 每个端点的完整说明(不只是"获取用户"这种废话)
- 请求参数的类型、约束、含义
- 响应结构的每个字段说明
- 错误码列表和触发条件
- 认证方式
- 实际调用示例
工具的话,OpenAPI(Swagger)规范是行业标准。配合Swagger UI或Redoc,既是文档又是调试工具。
文档写完了,发给调用方之前,自己先按照文档把每个接口调用一遍。你会发现文档里各种没说清楚的地方。
七、最后说几句
API设计没有完美答案,只有trade-off。但有些原则是普适的:
- 一致性:内部风格要统一,别这个接口用驼峰那个用下划线
- 可预测:按照文档来用,应该能正常工作
- 容错性:客户端可能犯错,API要有足够的校验和友好的错误提示
- 演进能力:一开始就考虑扩展性,别到时候改不动
好的API用起来的感觉就是"理所当然",坏的API用起来就是"这个设计是认真的吗"。
代码写出来是给别人用的,API更是。
以上,共勉。
有问题欢迎留言交流。当然,如果你说你的API被骂了,先别急着甩锅给调用方,看看是不是自己设计确实有问题。