如果你写过 API,你会发现世界上有两种 API:一种是让人用了想给你寄刀的,另一种是让人用了想给你介绍对象的。
作为一个写过无数接口、踩过无数坑的后端工程师,今天我们来聊聊那些年我们一起犯过的 RESTful API 设计错误,以及如何避免成为同事背后的诅咒对象。
一、URL 设计:别把接口写成谜语
我见过最离谱的 API URL 是这样的:
/api/v1/ugc/content/list?type=2&status=1&sort=desc
请问这个接口是干嘛的?猜对了算我输。
URL 应该是名词,不是动词。 记住这个黄金法则:
GET /users- 获取用户列表POST /users- 创建新用户GET /users/123- 获取指定用户PUT /users/123- 更新用户DELETE /users/123- 删除用户
资源要用复数!别问我为什么,这是 RESTful 的基本礼仪。
二、状态码:别总是返回 200
有些人写接口,返回永远是 200_OK,错误信息藏在 body 里的 code 字段:
{"code": 500, "message": "用户不存在"}
这是掩耳盗铃!HTTP 状态码是给谁用的?是给调用方用的!是给中间件用的!是给调试工具用的!你把它藏着掖着,跟把灭火器藏起来有什么区别?
正确的状态码使用:
200- 成功201- 创建成功400- 请求参数错误401- 未认证403- 无权限404- 资源不存在500- 服务器错误(慎用,除非真的到了山穷水尽的地步)
三、分页:没有分页的列表接口就是定时炸弹
如果你写了一个 GET /posts 返回所有帖子,恭喜你,你刚刚为公司的数据库埋下了一颗定时炸弹。
当数据量从 100 条增长到 100 万条,你的接口就会从"秒回"变成"超时",从"可靠"变成"故障"。
分页参数规范:
page- 页码,从 1 开始per_page- 每页数量,建议默认 20,最大 100
返回时记得带上分页元数据:
{
"data": [...],
"meta": {
"total": 1000,
"page": 1,
"per_page": 20,
"total_pages": 50
}
}
四、版本管理:别让旧接口成为技术债务
你的 API 总会有一天需要改结构。怎么办?直接改?做梦!
你永远不知道有多少下游服务在依赖你的接口。改坏一个字段,可能同时炸掉三条业务线。
版本策略:
- URL 版本:
/api/v1/users、/api/v2/users- 简单粗暴,容易理解 - Header 版本:
Accept: application/vnd.myapp.v2+json- 优雅但复杂
我的建议:URL 版本,简单直观。维护两个版本,给旧版本留足够的生命周期,给调用方足够的时间迁移。
五、幂等性:这东西比你想的重要
什么是幂等性?简单说就是:同一个请求执行一次和执行 N 次,效果是一样的。
GET /users/123 - 天然幂等,查多少次都不会变
DELETE /users/123 - 幂等,删除第一次之后,再删就是"不存在",不会报错
POST /users - 不幂等!每次创建都是新用户
PUT /users/123 - 幂等,同一个数据更新 N 次结果一样
为什么重要?因为网络会超时,因为客户端会重试。如果你的删除接口不幂等,客户端重试一次可能就真的删光了。
六、错误响应:给点有用的信息会死?
最气的错误响应是什么?
{"error": "An error occurred"}
请问是什么错误?服务器炸了?参数错了?还是你心情不好?
好的错误响应应该包含:
error- 错误类型(invalid_parameter、not_found等)message- 人类可读的错误描述details- 详细的错误信息(比如哪个字段错了)
{
"error": "validation_error",
"message": "请求参数验证失败",
"details": [
{
"field": "email",
"message": "邮箱格式不正确"
}
]
}
七、总结:好 API 的标准
一个好的 API,应该做到:
- 自文档化 - 看 URL 就知道是干嘛的
- 状态码明确 - 成功失败一目了然
- 分页必备 - 列表接口必须支持分页
- 版本规划 - 预留升级空间
- 幂等设计 - 允许安全重试
- 错误友好 - 出了问题能快速定位
最后,送大家一句话:API 写出来是给别人用的不是你自嗨的。 在你敲下每一个 endpoint 之前,想象一下对面那个调用你的同事。他可能在Debug一个奇怪的问题,可能在赶上线进度,可能已经在心里默默问候你了。
所以,做个人吧,写个人能看懂的 API。
~本文完~