RESTful API 为什么把程序员逼成了"URL装修工"?
干后端开发这几年,我悟出一个道理:写CRUD不难,难的是给CRUD起名字。
一个资源,叫/users还是/userList?查单个用户,是/users/123还是/getUser?id=123?删东西用DELETE还是POST?这些问题看似简单,但团队里每个人答案都不一样,于是你的API就变成了"URL装修现场"——每个程序员都在按自己的审美装修URL,结果交付的是一套混搭风格的两居室。
REST是什么?不是规范,是"约定"
很多人以为REST是一套严格规范,其实它只是一个论文里的概念,真正落地靠的是大家"说好了一起这么干"。Roy Fielding当年提出REST的时候,大概没想到会被程序员们玩成"起名大赛"。
REST的核心其实就几句话:一切皆资源,资源用URL表示,用HTTP动词描述操作,状态无记忆(Stateless)。听起来简单,但"一切皆资源"这个设定就够你喝一壶的——什么叫资源?
用户的订单是资源,订单里的某一条目算不算资源?商品的评论是资源,那"最近一周被点赞最多的评论"算不算资源?
真实答案:都行。你说算就算,你说不行就不行。REST不负责给你主持公道。
URL设计三大流派,你是哪一派?
流派一:REST原教旨主义
这一派的程序员看过Fielding的论文,对URL有着近乎强迫症般的执念:
GET /users/123/orders
GET /orders?status=pending&user_id=123
DELETE /orders/456
URL里不能出现动词,一切用HTTP方法表达。他们坚信,这是最"正确"的REST写法,每次设计URL都要问自己:这个操作能不能映射到一个资源上?
流派二:实用主义
这一派被现实毒打过,知道过度抽象只会让URL变成天书:
POST /users/123/orders/456/cancel
POST /users/123/orders/batch-create
GET /search?q=小龙虾+好吃
他们觉得search、cancel、batch这种词用就用了,程序员能看懂比"是否符合REST精神"更重要。
流派三:GraphQL崛起派
这一派直接掀桌子:URL是什么?不重要。一个请求告诉你我要什么数据,后端返回就是了。
POST /graphql
{
user(id: "123") {
name
orders(status: "pending") {
id
total
}
}
}
URL设计?不存在的。程序员终于可以专心写逻辑了,感动到流泪。
状态码,程序员的"已读不回"
HTTP状态码是另一个重灾区。我见过最离谱的API是这样的:
HTTP 200
{
"code": -1,
"message": "用户不存在",
"data": null
}
你200了,但业务逻辑失败了。这就像你跟人说"好的没问题",但转头就把事给拒了。对方还以为你答应了,等着收货呢。
状态码的滥用主要有几种:
- 永远200俱乐部:不管发生什么,HTTP状态码永远是200,具体错误藏在body里。这种API的错误处理全靠前端工程师人肉解析code字段。
- 状态码乱入:404表示"用户不存在",500表示"余额不足"。不是不能,但调试的时候你试试在日志里找原因。
- 正确的少数派:4xx是客户端错误,5xx是服务端错误,业务级别的错误用body里的code字段表达。这是相对健康的状态。
命名,我的头发主要死在这
URL命名是后端工程师和产品经理战争的第一线:
- 产品说:"用户"叫"用户"就好,简单。
- 后端说:"user"还是"customers"?复数还是单数?
- 客户端说:"getUserInfo"和"fetchUserInfo"和"loadUser"你们能不能统一一下?
我的经验是:用产品语言命名URL,用技术语言命名参数。URL是给人看的,参数是给代码读的。
GET /orders # 订单列表(产品语言)
GET /orders?status=pending&page=1&page_size=20 # 参数用技术语言
另外,复数名词是URL的事实标准。不用纠结users还是user_list,用/users就对了。所有主流API——GitHub、Stripe、Trello——全在用复数。
版本管理:API的"装修监理"
API versioning是个让人头大的问题,但不做版本管理的API迟早要还债。
三种常见方式:
# URL版本(GitHub、Trello等常用)
GET /v1/users/123
GET /v2/users/123
# Header版本
GET /users/123
API-Version: 2024-01-01
# Query参数版本(不推荐)
GET /users/123?version=2
URL版本最直观,但改动成本最高(所有客户端都要改)。Header版本优雅,但调试的时候得记得带Header,容易被忽略。Query参数最简单,但看起来不够"正规"。
我的建议:小型项目用Header版本,大型公开API用URL版本。除非你想让自己的API看起来像一个版本博物馆。
写在最后
RESTful API设计没有银弹,每个人都有自己的"最佳实践"。有人追求规范,有人追求实用,两边都没错——只要团队内部达成一致,风格统一,比死扣某个概念重要一百倍。
毕竟,你的API不是给Fielding看的,是给前端程序员和第三方开发者用的。让他们少掉头发,比让URL看起来更符合REST精神,有价值多了。
下次再有人问你"这个URL符不符合REST规范",你可以直接回他:符合不符合不知道,反正能跑就是好URL。
毕竟,我们都是URL装修工,手里有锤子,URL就是钉子。🏠