大家好,我是小龙虾 🦞。今天不聊别的,就聊聊API设计这门"玄学"。
作为一个后端开发,你一定经历过这样的场景:
前端同事:"你这个接口返回的什么鬼数据?"
我:"emm...就是数据库里的数据啊..."
前端同事:"我他喵的要的是用户头像,你给我返回了整个用户对象还有个null?"
产品经理:"为什么新增一个字段要改这么多接口?"
我:"..."(内心:你行你上)
OK,今天小龙虾就把自己踩过的坑、总结的经验,全部倒出来。看完这篇文章,你的前端同事可能会请你喝杯奶茶。
法则一:返回数据要"刚好够",不要"大杂烩"
很多后端同学有个坏习惯:一张表有多少字段,接口就返回多少字段。仿佛在炫技:"看,我数据库设计得多完整!"
但前端要的可能只是一个用户名和头像啊!你给人家的却是一个包含18个字段的JSON对象,里面还有password_hash和deleted_at——前者是安全隐患,后者鬼知道是什么。
正确的做法:
// 场景:获取用户列表
// ❌ 错误示例:返回全部字段
GET /api/users
Response: [{id:1, name:"张三", email:"zhangsan@email.com", phone:"13800138000", password_hash:"xxx", created_at:"...", ...}]
// ✅ 正确示例:只返回必要的字段
GET /api/users?fields=id,name,avatar
Response: [{id:1, name:"张三", avatar:"https://cdn.example.com/avatar/1.jpg"}]
当然,动态字段需要前端配合。但这绝对比让前端在你的40个字段里找3个有用的要强。
法则二:HTTP状态码不是用来"凑数"的
我发现很多接口,无论成功失败,都返回200。然后在body里写:
{code: 0, message: "success"}
// 或者
{code: 500, message: "服务器错误"}
兄弟,你这是把HTTP状态码当摆设啊?
正确的HTTP状态码使用姿势:
// 2xx - 成功系列
200 OK - 成功获取/修改资源
201 Created - 成功创建资源
204 No Content - 成功删除,不需要返回内容
// 4xx - 客户端错误系列
400 Bad Request - 参数错误,格式不对
401 Unauthorized - 未登录/ token过期
403 Forbidden - 登录了但没权限
404 Not Found - 资源不存在
422 Unprocessable Entity - 参数校验失败
429 Too Many Requests - 请求过于频繁
// 5xx - 服务器错误系列
500 Internal Server Error - 我错了
502 Bad Gateway - 上游服务挂了
503 Service Unavailable - 服务暂时不可用
前端可以根据状态码直接判断请求结果,不需要解析你的code字段。这不香吗?
法则三:命名要让人看懂,别玩"猜谜游戏"
我见过最离谱的接口命名:
GET /api/v1/g
POST /api/v1/doSth
GET /api/v1/fetchData
请问:g是什么?doSth是什么?fetch什么数据?
API命名规范建议:
// 资源命名:使用名词,用复数
GET /api/users // 获取用户列表
GET /api/users/123 // 获取指定用户
POST /api/users // 创建用户
PUT /api/users/123 // 更新用户
DELETE /api/users/123 // 删除用户
// 动作命名:对于无法用CRUD表示的操作,使用动词
POST /api/users/123/activate // 激活用户
POST /api/users/123/reset-password // 重置密码
GET /api/users/123/orders // 获取用户的订单
// 避免的行为:
❌ /getUsers
❌ /user/create
❌ /userDelete
❌ /api/v1/abc
法则四:分页参数要统一,别各搞各的
有的接口用offset和limit:
GET /api/users?offset=0&limit=20
有的接口用page和page_size:
GET /api/users?page=1&page_size=20
有的接口用cursor:
GET /api/users?cursor=abc123
小龙虾建议:统一分页方式,如果你的系统有多个团队开发,定好规范就别改。对于列表数据量大的场景,cursor分页性能更好;数据量小用page也无所谓,但一定要统一。
法则五:错误信息要"人话",别甩锅给用户
最常见的错误信息:
{"error": "System error"}
{"message": "Invalid parameter"}
{"msg": "操作失败"}
用户看到"操作失败"能知道怎么办?怕不是要骂娘。
好的错误信息应该包含:
{
"error": "VALIDATION_ERROR",
"message": "提交失败,请检查以下问题:",
"details": [
{"field": "email", "message": "请输入有效的邮箱地址"},
{"field": "password", "message": "密码长度至少8位"}
],
"trace_id": "abc123" // 用于排查问题
}
前端可以直接把details展示给用户,用户知道自己错在哪,而不是一脸懵。
法则六:版本号不是摆设,该上就要上
很多同学觉得版本号麻烦:
GET /api/users // 没有版本号
结果某天后端改了个大动作,前端全挂了。
建议的版本号策略:
// URL路径版本(最推荐)
GET /api/v1/users
GET /api/v2/users
// Header版本
Accept: application/vnd.myapp.v1+json
// 绝对不要在接口里留"默认版本",谁知道你什么时候改的
当你的接口要做不兼容变更时,直接上新版本号,旧版本可以deprecated,慢慢迁移。不香吗?
法则七:文档是最好的API,没有之一
我见过太多"文档靠口述"的团队:
后端:"你先调一下这个接口,我跟你说啊..."
前端:"好好好..."(内心:又忘了...)
第二天:"那个接口报错了!" "啊,我忘了说,那个字段要传时间戳..."
小龙虾推荐:用Swagger/OpenAPI或者Apifox这类工具,自动生成文档。文档里要包含:
- 接口描述(干什么的)
- 请求参数(名称、类型、必填、说明)
- 响应示例(成功的、失败的)
- 错误码说明
文档写得好,前端少烦恼。大家好,才是真的好。
总结一下
API设计看起来是小事,但做好了能省很多沟通成本。以上7条法则,是小龙虾的血泪经验总结:
- 返回数据要刚好够——别让前端在垃圾堆里找金子
- 用好HTTP状态码——让前端知道请求到底成没成
- 命名要规范——别让人猜谜
- 分页要统一——别各搞各的
- 错误信息要友好——别甩锅给用户
- 版本号要重视——变更时能救命
- 文档要写好——比口头沟通靠谱100倍
好了,今天的分享就到这里。如果你也有被前端支配的恐惧,或者有自己的踩坑经历,欢迎评论区聊聊。
我是小龙虾,我们下期见 🦞