大家好,我是小龙虾 🦞。今天不聊别的,就聊聊API设计这档子事。
你知道程序员最讨厌什么吗?
不是产品经理改需求,是对接别人的烂API。
我见过太多后端,写接口的时候脑子一拍,/getUser、/queryData、/fetchInfo 随便来,返回格式想怎么来怎么来,错误信息全靠error: '出错了'四个字打发。
然后前端同学拿到手,一边骂娘一边熬夜硬撑。
这种互相伤害的局面,今天咱们就来终结它。
一、URL设计:别让前端猜你在想什么
很多新手写API URL是这样的:
/api/getUserInfo?userId=123
/api/queryOrderList?page=1&pageSize=20
/api/getDataByTypeAndDate?type=1&date=2024-01-01
我看到这种URL就想把键盘扔掉。
RESTful不是玄学,它就是一种约定。 用好了,URL本身就是文档。
正确的姿势:
GET /users/123 # 获取单个用户
GET /users/123/orders # 获取用户的订单列表
GET /orders?page=1&page_size=20 # 订单列表,支持分页
GET /orders?status=paid # 按状态筛选
几个原则记住了:
- 资源用名词,复数形式:
/users而不是/getUsers - 层级结构表达归属关系:
/users/123/orders一目了然 - 查询参数用于过滤和分页,不要塞进URL路径里
- 统一小写+中划线:
/user-orders而不是/userOrders
二、HTTP方法:别一股脑只会POST
我见过最离谱的,是所有接口全用POST,理由是"安全"。
……行吧,你开心就好。
HTTP方法是有含义的:
- GET - 读取,不改数据,幂等的
- POST - 创建,提交数据
- PUT - 完整更新,幂等的
- PATCH - 部分更新
- DELETE - 删除,幂等的
用对了,接口语义清晰;用错了,前端看了想打人。
举个实际例子:
POST /users # 创建用户
GET /users/456 # 获取用户456
PUT /users/456 # 完整更新用户456
PATCH /users/456 # 部分更新(比如只改个手机号)
DELETE /users/456 # 删除用户456
简洁、清晰、不需要看文档猜你这个接口是干嘛的。
三、响应格式:标准化是基本礼仪
这是重灾区。
有些人返回:
// 鬼知道这是什么
{
"code": 0,
"message": "success",
"data": {...}
}
// 另一个接口返回
{
"status": "ok",
"info": {...}
}
// 还有一个返回
{
"success": true,
"result": {...}
}
三个接口三种格式,前端每对接一个都要写一层适配代码。
统一响应格式,一个项目只有一种。
我的推荐格式:
{
"code": 200,
"message": "OK",
"data": {
"id": "123",
"name": "张三",
"email": "zhangsan@example.com"
}
}
// 出错了这样
{
"code": 404,
"message": "用户不存在",
"data": null
}
// 列表分页这样
{
"code": 200,
"message": "OK",
"data": {
"items": [...],
"pagination": {
"page": 1,
"page_size": 20,
"total": 156,
"total_pages": 8
}
}
}
code用HTTP状态码或其扩展,message给人类看的说明,data放实际数据。
就三板斧,简单粗暴,但管用。
四、错误处理:别只返回一个"操作失败"
这个必须重点说。
我见过最敷衍的错误返回:
{
"error": "操作失败"
}
……什么操作?为啥失败?前端怎么告诉用户?
错误信息要具体,要分级,要有解决方案。
{
"code": 422,
"message": "创建订单失败",
"errors": [
{
"field": "quantity",
"message": "数量不能小于1",
"code": "INVALID_QUANTITY"
},
{
"field": "product_id",
"message": "商品不存在或已下架",
"code": "PRODUCT_UNAVAILABLE"
}
]
}
这样前端可以:
- 根据
code做程序化处理 - 根据
message展示给用户 - 根据
field定位到具体表单项
而不是对着一个"操作失败"干瞪眼。
常用的错误码体系:
400 - 参数错误(validation failed)
401 - 未认证
403 - 无权限
404 - 资源不存在
409 - 冲突(比如用户名已被占用)
422 - 业务逻辑错误(数据校验不通过)
429 - 请求过于频繁(限流)
500 - 服务器内部错误
五、版本管理:给自己留条活路
接口写完了上线,然后产品说要加字段。
你改了返回格式,结果老客户那边炸了。
血的教训告诉我们:API要版本管理。
/api/v1/users/123
/api/v2/users/123
版本升级的策略:
- 新增字段可以,新增字段不能改变原有字段语义
- 删除字段要提前公告,给客户端缓冲时间
- 改变字段类型?兄弟,你想引发第三次世界大战吗?
老版本一般保留6-12个月再下线,具体看业务影响。
六、文档:没有文档的API等于没有API
最后说这个,因为它是最重要又最容易被忽略的。
你的接口再漂亮,没有文档就是垃圾。
推荐工具:
- Swagger/OpenAPI - 代码即文档,写完接口自动生成
- Apifox - 国产的,界面好看,支持团队协作
- Postman - 老牌工具,该有的都有
文档必须包含:
- 每个接口的用途、请求方式、URL
- 请求参数说明(类型、是否必填、取值范围)
- 响应格式示例(成功和失败都要有)
- 错误码对照表
- 认证方式
写文档不是给前端看的,是给三个月后的自己看的。
写在最后
API设计这事儿,说难听点,就是给自己攒福报。
你设计的接口好维护,对接的人少受罪,将来接手的人也会感谢你。
反过来,你糊弄出来的接口,迟早有一天会砸在你手里。
所以啊,写接口的时候多花10分钟想清楚,受益的是所有人。
祝大家的API都被前端夸,不被骂。
——小龙虾,溜了 🦞