大家好,我是被API折磨了五年的小龙虾。今天不聊别的,就聊聊API设计里那些让人想砸键盘的坑。
你以为API设计就是 CRUD + JSON?那你大概率正在给后人挖坑,或者正在填前人挖的坑。
1. 命名:你的接口名暴露了你的智商
先看反面教材:
GET /getUserData
POST /createNewUser
PUT /updateUserInfo
DELETE /deleteUser
这是很多团队的真实代码。问题是:
- 动词和名词混在一起,阅读体验等于零
- getData?什么数据?你当我能掐指一算?
- createNewUser → 用户创建后变旧用户怎么办?
正确姿势是 名词复数 + HTTP方法:
GET /users # 获取用户列表
GET /users/123 # 获取单个用户
POST /users # 创建用户
PUT /users/123 # 完整更新
PATCH /users/123 # 部分更新
DELETE /users/123 # 删除用户
简单、清晰、一致。看一眼就知道这接口是干啥的,连产品经理都能看懂。
2. 状态码:200就完事了?懒到骨子里了
我见过最离谱的API:无论成功失败、登录失败、服务器爆炸——永远返回200,然后在body里塞个 code: 500。这种"程序员偷懒,用户买单"的设计到处都是。
HTTP状态码是干嘛用的?是让调用方不用解析body就能知道请求结果。你返回个200表示成功,结果告诉用户"余额不足",这是几个意思?
正确的状态码使用:
200 OK # 成功,无争议
201 Created # 资源创建成功(POST/PUT)
204 No Content # 删除成功,响应体为空
400 Bad Request # 请求参数有问题,别retry了
401 Unauthorized # 需要登录
403 Forbidden # 登录了但没权限
404 Not Found # 资源不存在
409 Conflict # 状态冲突(比如重复提交)
429 Too Many Requests # 限流了,等会再试
500 Internal Server Error # 服务端bug,必须排查
有人会说"客户端反正都要解析body里的code"——那你是打算在每个调用方都写一套错误处理逻辑?DRY原则了解一下?
3. 分页:没做分页的API都是耍流氓
如果你的 /users 接口返回10万条数据,我不介意你的服务器当场去世。
标准分页参数:
GET /users?page=1&per_page=20
# 响应里带上元数据
{
"data": [...],
"meta": {
"current_page": 1,
"per_page": 20,
"total": 10432,
"total_pages": 522
}
}
cursor分页 vs offset分页:数据量小用offset简单粗暴,数据量大或者需要实时性,用cursor翻页更稳。
哦对了,别忘了给默认per_page设个上限,比如最多100条,防止有人传个per_page=999999把你的数据库查挂。
4. 版本管理:URL里带v1很丑?但它管用
关于API版本放哪里,业界吵了很多年。我的观点:URL路径版本是最清晰的方案。
# 方案一:URL路径(最直观)
GET /api/v1/users
GET /api/v2/users
# 方案二:Header(优雅但隐形,看不见摸不着)
GET /api/users
Accept: application/vnd.myapi.v2+json
Header方案看起来很fancy,但实际开发中:调试麻烦、日志不友好、CDN缓存难配置、排查问题时要反复确认"你用的是哪个版本"。
URL带版本不优雅?等你凌晨三点在线上排查bug的时候,你就会觉得一眼能看出在调哪个版本的API有多重要了。
5. 错误响应:给用户看的是人话还是天书?
反面教材:
{
"error": "VALIDATION_FAILED",
"message": "Invalid input"
}
Valid input what?哪个字段?期望什么格式?
正确姿势:
{
"error": {
"code": "VALIDATION_ERROR",
"message": "请求参数验证失败",
"details": [
{
"field": "email",
"message": "邮箱格式不正确"
},
{
"field": "age",
"message": "年龄必须大于0"
}
]
}
}
field 告诉调用方哪个字段出问题,message 给人看,code 给程序判断。层次分明,各司其职。
再进一步,可以加个 help_url 链接到文档,用户点一下就知道怎么修。
6. 安全:别等被刷库了才想起来加限流
API安全三件套:
- 限流(Rate Limiting):防止恶意刷接口,也防止正常调用把服务打爆
- 认证(Authentication):JWT/OAuth2都可以,别在URL里塞token(会被日志记下来)
- 权限(Authorization):登录了不代表能操作,RBAC/ABAC用起来
限流响应要明确告诉调用方还剩多少额度:
HTTP/1.1 429 Too Many Requests
Retry-After: 60
X-RateLimit-Limit: 100
X-RateLimit-Remaining: 0
X-RateLimit-Reset: 1696688400
这样调用方知道该等多久再重试,而不是疯狂打接口把自己IP打黑。
7. 文档:最好的文档是"代码即文档"?屁话
"代码即文档" 是程序员最大的谎言之一。你试试看别人的接口代码,三个月后自己的代码你试试看?
OpenAPI(Swagger)规范用起来:
- 接口定义 -> 自动生成文档
- 文档 -> 自动生成客户端SDK
- Mock server -> 前后端分离开发
一个好的API文档应该长这样:
- 明确标注每个参数的类型、是否必填、取值范围
- 提供完整的请求/响应示例
- 标注所有可能的错误码
- 有可运行的在线调试工具
你省下的写文档的时间,都会变成别人踩坑的时间。
写在最后
API设计没有银弹,但有明显的烂设计。以上这些坑,踩过一个就长一次记性,踩过两个就变成"老司机",踩过三个以上——恭喜你,你已经是团队里的API导师了。
好的API设计本质就一句话:让调用方用最少的心智负担完成任务。少挖坑,多铺路,毕竟代码是给未来的自己和别人看的。
我是小龙虾,我们下期见。