RESTful API 设计那些事儿:别让你的接口变成一场灾难
开门见山,我见过太多所谓的"RESTful API",实际上是RESTful的灾难现场。URL 写得跟玩似的,状态码返回 200 表示"你密码错了",HTTP 方法?不存在的,全部 POST 走天下。
作为一个在后端泥潭里滚了好几年的程序员,今天来聊聊怎么设计一个让人想给你点star而不是提issue的API。
一、URL设计:名字即契约,别随便起
URL是什么?是你的API的门牌号。一个好的URL应该:
- 名词复数,资源为王:/users 而不是 /getUsers,不是 /user,也不是 /fetchUserById
- 层级清晰,不要嵌套过深:/users/123/orders/456 这种两层还行,三层以上就该想想是不是设计有问题了
- 不用动词,HTTP方法就是动词:GET /users 查用户,POST /users 创建用户,DELETE /users/123 删除用户
✅ GET /articles # 获取文章列表
✅ GET /articles/42 # 获取单篇文章
✅ POST /articles # 创建文章
✅ PUT /articles/42 # 更新文章
✅ DELETE /articles/42 # 删除文章
❌ GET /getArticle?id=42
❌ POST /deleteArticle
❌ POST /createNewUser.php
二、状态码:别再返回200表示"服务器炸了"
这是重灾区。我见过最离谱的API,所有响应都返回200,然后在body里写 {"code": 500, "msg": "服务器内部错误"}。兄弟,你这是精神分裂式API设计。
HTTP状态码是干嘛用的?是让调用方快速判断结果的,不是你随手填的数字。
200 OK # 成功,别滥用
201 Created # 创建资源成功
204 No Content # 删除成功,无返回体
400 Bad Request # 参数校验失败
401 Unauthorized # 没登录
403 Forbidden # 登录了但没权限
404 Not Found # 资源不存在
422 Unprocessable Entity # 业务校验失败(比如余额不足)
429 Too Many Requests # 请求太频繁了
500 Internal Server Error # 服务器真的炸了
记住:能用状态码表达的意思,别放body里。你又不是在写小说,不需要那么多细节描写。
三、错误响应:给开发者一条活路
当你的API报错时,请务必告诉调用者:发生了什么、错在哪、怎么改。
{
"error": {
"code": "INVALID_PARAMETER",
"message": "手机号格式不正确",
"detail": {
"field": "phone",
"value": "12345",
"hint": "请输入11位手机号"
},
"request_id": "req_abc123xyz" // 这个很重要,排查问题全靠它
}
}
request_id一定要有。当用户在群里骂你API烂的时候,有了这个ID你才能快速定位问题,而不是对着日志发呆。
四、分页:列表接口的灵魂
没有分页的列表接口,在数据量上来之后就是DoS攻击工具。
GET /articles?page=1&per_page=20&sort=created_at&order=desc
响应应该长这样:
{
"data": [...],
"pagination": {
"current_page": 1,
"per_page": 20,
"total": 342,
"total_pages": 18,
"has_next": true,
"has_prev": false
}
}
有人问:cursor分页和offset分页哪个好?简单说:数据会变动的场景用cursor(类似推特timeline),数据相对稳定的用offset。别无脑offset,数据量大了慢死你。
五、版本管理:让你的API活下去
API是要迭代的,但不能因为迭代就把现有用户全干掉。版本管理了解一下:
✅ GET /v1/users
✅ GET /v2/users
❌ GET /users/v1
放在URL路径里是最清晰的方式。有人喜欢放header里,说是"更优雅"——说实话,调试的时候你就知道多不优雅了。URL能直接试,谁用谁爽。
版本升级的原则:渐进式废弃,别一刀切。v1deprecated了,给个缓冲期,提前通知,别搞突然袭击。
六、安全:别让API变成大门敞开的保险箱
- 认证用JWT或OAuth2,别自己发明轮子:什么md5(password + timestamp)签名,听着就不靠谱
- 敏感操作要验权:读取和写入的权限要分开管理
- 请求要限流:防止被人薅羊毛或者意外循环调用把你打挂
- 输入要校验:SQL注入、XSS这些基础攻击,99%是因为懒
# 限流响应头示例
X-RateLimit-Limit: 1000
X-RateLimit-Remaining: 456
X-RateLimit-Reset: 1623945600
七、最容易踩的坑
1. 穷调用问题:一次获取用户信息需要调用 /user → /user/posts → /posts/123/comments,10次请求拿一页数据。解决方案:GraphQL或BFF聚合了解一下。
2. 过度设计:一个简单的CRUD,非要搞什么CQRS、事件溯源。兄弟,先跑起来,再考虑优化。
3. 文档缺失或过时:代码和文档不一致,这不是,这是日常。推荐用OpenAPI/Swagger规范来写文档,代码即文档。
结语
API设计没有绝对的标准,但有一些底线:让调用者能猜到用法,让后来者能看懂逻辑,让运维能快速定位问题。
下次设计API之前,先问自己三个问题:
- 这个URL我能不能直接丢给postman测试?
- 出错了,我有没有给足够的错误信息?
- 三个月后我自己看这段代码,会不会想骂人?
如果都是yes,那你大概率走在正确的路上。
记住:好的API是给开发者用的,也是给未来的自己用的。且写且珍惜。