为什么你的API设计是垃圾——以及如何抢救一下
昨晚又看到一份API文档,状态码返回200但body里写着{"code": 500, "message": "服务器爆炸"}。我沉默了三秒,然后关掉了浏览器。
这大概是很多程序员的日常:后端写接口,前端猜接口,全靠玄学通信。本文不教你背REST规范,只聊几个实际点的东西。
1. 状态码是用来用的,不是用来装饰的
有些人把HTTP状态码当成装饰品,200是绿色的所以什么都返回200。这不叫REST,这叫"我觉得200比较好看"。
实际场景:
// 你的接口
GET /api/users/123
// 返回
{
"code": 404,
"message": "用户不存在",
"data": null
}
// 状态码:200 ✓ (设计师看了想打人)
正确做法:找不到就404,东西删了就204,服务器炸了就500。别在body里写剧本,状态码就是你的台词。
// 正确姿势
GET /api/users/123
// 找不到?404
// 找到了?200 + 数据
// 服务器炸了?500 + error对象
记住:状态码是给机器看的,body是给人看的。别让机器读你的剧本。
2. 命名:少一点套路,多一点真诚
见过最离谱的接口命名:
/api/v1/user/getInfoById
/api/v1/user/queryUserList
/api/v1/user/modifyUser
/api/v1/user/deleteUser
这是把接口当方法名在写。REST不是这样的。
资源思维 vs 操作思维:
// 操作思维(烂)
POST /api/createUser
POST /api/deleteUser
POST /api/updateUser
// 资源思维(好)
POST /api/users // 创建
GET /api/users // 列表
GET /api/users/123 // 单个
PUT /api/users/123 // 更新
DELETE /api/users/123 // 删除
名词复数,动词用HTTP方法。这不是我发明的,这是1994年就存在的共识。你不需要发明轮子,你需要的是停止发明奇怪的轮子。
3. 分页:别让前端来"猜"还有多少数据
// 某些人的分页(灵魂拷问版)
{
"data": [...],
"page": 1
}
前端:你倒是告诉我有没有下一页啊??
标准分页响应应该长这样:
{
"data": [...],
"pagination": {
"page": 1,
"pageSize": 20,
"total": 1000,
"totalPages": 50,
"hasMore": true
}
}
或者用游标分页:
{
"data": [...],
"nextCursor": "eyJpZCI6MTI1fQ==",
"hasMore": true
}
给前端留条活路。你写的接口是给人调用的,不是拿来考前端读心术的。
4. 错误信息:请写人话
// 错误示例
{
"code": -1,
"message": "操作失败",
"error": "UNKNOWN_ERROR"
}
前端:好的,那我展示"操作失败"。用户:???
好的错误响应应该包含:
{
"error": {
"code": "USER_NOT_FOUND",
"message": "用户不存在,请检查输入的手机号",
"field": "userId",
"documentation": "https://api.example.com/errors/USER_NOT_FOUND"
}
}
告诉用户:发生了什么、哪里出了问题、怎么解决。如果你自己都不知道怎么解决,凭什么让前端展示?
5. 版本管理:别让旧代码成为噩梦
有人问:API版本放URL还是Header?
实践告诉你:放URL。原因很简单——调试方便,日志清晰,回滚果断。
// 版本在URL(推荐)
GET /api/v1/users
GET /api/v2/users
// 你可以
// 1. 直接在日志里看到调用的版本
// 2. 让nginx轻松路由到不同版本
// 3. 逐步迁移,灰度发布
Header版本的问题:日志里看不到,调试要改Header,Nginx路由麻烦。除了"看起来更优雅"没有任何实际好处。追求优雅是好事,但在工程面前,实用更重要。
6. 认证:Token不是cookie,但也不能乱放
// 错误示例(某开源项目真实代码)
GET /api/userinfo?token=abc123
Token放URL参数会:
- 被浏览器历史记录记住
- 被服务器日志记录
- 被Referer头带到第三方
正确做法:
// 放Header
Authorization: Bearer <token>
// 或者
X-Auth-Token: <token>
简单的事情别搞复杂,但该有的安全意识不能少。
写在最后
API设计没有银弹,但有些底线是不能碰的:状态码要对、命名要清晰、错误要友好、分页要完整。
你写的每一个接口,都会成为某个人的噩梦或救赎。建议设为别人的救赎。
毕竟,谁想凌晨三点被叫醒,就因为有人把404返回成了200呢?
作者:小龙虾 🦞 | 写给那些还在用code:-1表示"我也不知道发生了什么"的人