先说个真实故事。我有个朋友(不是我),给移动端写了一套接口,返回数据长这样:
{
"code": 200,
"message": "success",
"data": {
"result": [
{
"id": 1,
"name": "产品A",
"price": "99.9",
"hasOwnProperty": true
}
]
}
}
然后产品经理问他:为什么价格是字符串?他说:方便前端拼接啊。
我当时在旁边差点把可乐喷出来。这不是API设计,这是行为艺术。
一、好的API,从不让人猜
RESTful API 设计规范已经出来很多年了,但真正遵守的没几个。不是规范太难,是很多人懒得理解「表象一致性」这件事。
什么叫表象一致性?就是你决定了一套规则,这套规则要从头到尾一致执行,不能今天返回数组,明天返回对象,后天返回字符串。大概类似这样:
// 统一响应格式 - 选一种,不要混搭
{
"code": 0,
"data": {},
"msg": ""
}
// 或者
{
"status": "success",
"payload": {},
"error": null
}
选好了就别动。团队里所有人、所有接口,都用这一套。谁搞特殊,谁就是团队公敌。
二、HTTP 状态码不是装饰品
很多后端写接口,甭管发生什么,返回永远是 200,然后在 body 里写 {"code": 500, "msg": "服务器冒烟了"}。
我就想问:客户端都收到 200 了,它怎么知道出错了?它还得再解析一遍 body?这不是给自己找麻烦吗?
HTTP 状态码是有含义的,该用就用:
200- 成功,别犹豫201- 资源创建成功(POST 返回这个很体面)400- 客户端参数有问题,别甩锅给后端401- 没登录,去登录403- 登录了但没权限,别挣扎404- 资源不存在,不是我们的锅500- 服务器炸了,这个锅后端背
有些人说「国内都这样」,国内都这样不代表对。规范存在的意义不是让你遵守的,是让你的接口对别人来说好用的。
三、命名这件事,懒不得
接口命名是重灾区。我见过最离谱的:
GET /getUserInfo
POST /doLogin
DELETE /delOrderById
拜托,HTTP 动词已经是动作了,你的 URL 里再放动词,这不是叠床架屋吗?REST 规范说了:URL 是资源,不是动作。
正确姿势:
GET /users/123 # 获取用户
POST /users # 创建用户
PUT /users/123 # 更新用户
DELETE /users/123 # 删除用户
简洁、清晰、一目了然。HTTP 动词已经告诉你这是查还是改还是删了,URL 不需要再重复强调。
还有一个坑:命名风格混搭。有人用 camelCase,有人用 snake_case,有人用 PascalCase。选一种,全站统一。JavaScript 生态推荐 camelCase,Python 生态推荐 snake_case,但这不重要,重要的是「统一」。
四、分页不是奢侈品
当你返回的数据可能超过几十条时,请用分页。不是可选项,是必选项。
最简单的分页参数:
GET /articles?page=1&per_page=20
返回结果里带上 metadata:
{
"data": [...],
"pagination": {
"page": 1,
"per_page": 20,
"total": 156,
"total_pages": 8
}
}
有人问:我数据量不大,要不要分页?答案是:要。今天数据量不大,不代表明天数据量不大。提前做好,比以后改好。
五、版本管理:给自己留条活路
API 肯定会变。字段会新增、会废弃、会有breaking change。怎么办?
在 URL 里加版本号:
/api/v1/users
/api/v2/users
新老版本共存,给客户端足够的迁移时间。等所有用户都切换到 v2 了,再把 v1 下线。
有人觉得这样麻烦,想用 Header 做版本管理。我只能说:你开心就好。实际上 URL 版本是最直观、最容易调试、最不容易出错的方案,别没事找事。
六、错误信息要像个道歉
错误信息不是用来给后端自己看的,是给调用方看的。一个好的错误响应应该:
- 告诉调用方什么错了
- 告诉调用方怎么修复(如果能告诉的话)
- 给一个唯一的错误码,方便排查
错误示例:
{
"error": "操作失败"
}
这说了等于没说。什么叫操作失败?数据库挂了?权限不足?还是你参数传错了?
正确示范:
{
"code": 40001,
"message": "手机号格式不正确,请输入11位数字",
"field": "phone"
}
这才是让人能干活的信息。
写在最后
API 设计这事儿,说难不难,说简单不简单。核心就一句话:让你的接口对调用方来说,是可预期的、可信赖的。
不要让调用方去猜你的返回格式。不要让调用方去猜你的字段名是 camelCase 还是 snake_case。不要让调用方在 200 的响应里去找错误信息。
好的 API 就像好的文档,存在感越低,价值越高。当调用方用得顺手的,不会想起你;当调用方开始频繁和你打交道的时候,说明你的设计出问题了。
少给自己埋雷,多给别人方便。这是最朴素的设计哲学,也是最难做到的。