入行这么多年,看了无数个项目,我总结出一个真理:程序员最擅长的两件事,一是写bug,二是把自己的API搞得跟天书似的。
今天咱们就来聊聊,那些年我们一起踩过的API设计坑,以及怎么爬出来。
一、URL设计:你是在写诗还是在写代码?
见过最离谱的API长这样:
GET /api/v2/internal/user/123456/orders/latest?type=success&sort=desc&format=json
我就想问一句,你是故意的还是不小心的?
好的URL应该像说话一样自然:
GET /users/123456/orders?status=completed
记住几个原则:
- 名词优于动词:/users 而不是 /getUsers,/orders 而不是 /fetchOrders
- 层级别太深:超过三级你就该反思人生了
- 小写加横线:别搞什么驼峰命名,/user-orders 不是 /userOrders
- 避免冗余:/users/123 够了,别搞成 /api/v1/users/getUserById/123
二、HTTP方法:GET和POST都不是万能钥匙
有人把POST当万能钥匙,有人只会用GET。这都不对。
正确的打开方式:
- GET - 读取资源,就该是只读的,别在GET里改数据
- POST - 创建资源,比如新建用户
- PUT - 完整更新资源,所有字段都得传
- PATCH - 部分更新,只传要改的字段
- DELETE - 删除资源,别用POST模拟删除
最搞笑的是见过这种:
POST /users/delete
我都想问他,你是在删除用户,还是在创建一条删除记录?
三、状态码:200 OK不是万能回复
见过最骚的操作:所有接口都返回200,然后在body里加个code字段表示错误。
{
"code": 500,
"message": "服务器炸了",
"data": null
}
你这是200,但你真的OK吗?
正确姿势:
- 200 - 成功,毋庸置疑
- 201 - 创建成功,比如新建了用户
- 400 - 客户端参数有问题,别啥都400,有时候是422更合适
- 401 - 没登录就访问
- 403 - 登录了但没权限
- 404 - 资源不存在,别什么都404
- 500 - 真的出问题了,别啥锅都让500背
四、返回结构:给我一个准话行不行?
这是重灾区,每个项目都有自己的"特色":
版本A:裸数据流派
["张三", "李四", "王五"]
版本B:包装过度派
{
"code": 0,
"message": "success",
"data": {
"code": 0,
"message": "success",
"data": {
"code": 0,
"message": "success",
"data": ["张三", "李四", "王五"]
}
}
}
版本C:随心所欲派
{"ret": 0, "msg": "成功", "result": [...], "list": [...], "data": {...}}
我求求你们了,开开会,定个规范,行吗?
推荐的结构:
{
"data": [...],
"meta": {
"total": 100,
"page": 1,
"per_page": 20
},
"error": null
}
或者直接用标准的状态码,body里就放数据,别搞那些花里胡哨的包装。
五、分页:别让我猜谜
分页这个事,也是百花齐放:
// 派系一:offset + limit
GET /users?offset=20&limit=10
// 派系二:page + size
GET /users?page=3&size=10
// 派系三:cursor
GET /users?cursor=abc123&limit=10
// 派系四:已看过的ID
GET /users?after_id=20&limit=10
你用哪个都行,但选定了就别换,而且文档里写清楚。最怕的是接口文档写的是page+size,实际用的是offset+limit,调用方一脸懵逼。
六、文档:没有文档的API就是在耍流氓
我见过最离谱的文档就一句话:
POST /users - 创建用户
然后呢?参数呢?返回值呢?错误码呢?
好文档应该包含:
- 接口用途(说人话)
- 请求参数(含类型、必填/可选、取值范围)
- 返回值(成功和失败都要写)
- 示例(请求+响应)
- 认证方式
- 限流说明
工具的话,Swagger/OpenAPI、Postman、Apifox都行,但工具只是辅助,内容才是根本。
七、版本控制:升级有风险,打招呼是美德
接口要升级了,怎么处理旧版本?
// 方案一:URL版本号(最常见)
GET /api/v1/users
GET /api/v2/users
// 方案二:Header里指定
GET /api/users
Accept: application/vnd.api+json; version=2
不管用哪种,旧版本要有退路。要么延长维护期,要么给足够的迁移时间。最恶心的是:周一说升级,周三就下线旧版,调用方当场去世。
总结
API设计这事儿,本质上是在跟调用你接口的人沟通。你写代码的时候多替对方想想,以后就会少挨很多骂。
记住这个心法:简单 > 复杂,清晰 > 隐晦,一致 > 个性。
最后送大家一句话:你的API,今天好好设计,明天少写注释。
散会。