4、资源建模与URL设计归纳总结
资源建模和URL设计,是API设计的起点,也是整个系统的骨架。说实话,骨架歪了,后面再怎么填肉也拧巴。我见过不少团队,上来就开撸接口,结果到后期维护时,光URL就够改八遍。
这章,我们把前面几章分散的知识点串起来,做个系统梳理。
资源建模的核心:识别“名词”
API设计的本质,是对业务领域内的“资源”进行建模。资源,就是那些你需要在系统中增删改查的“东西”。比如用户、订单、商品、文章。它们都是名词。
怎么识别?我有个笨办法,但是很管用:找业务流程里的实体。拿电商系统举例,订单、商品、用户、购物车,这就是核心资源。支付记录、物流信息,这是附属资源。
资源建模三要素
- 唯一标识:每个资源实例必须有一个唯一的ID或标识符。
- 元数据:描述资源属性的数据。比如订单的金额、状态、创建时间。
- 关系:资源之间的关联。比如一个订单包含多个商品。
你想想看,如果连资源都没想清楚,就开始定义URL,那URL大概率会很混乱。我以前处理过一个项目,把“用户创建订单”做成了一个独立的资源叫“UserOrderCreateAction”,这明显是把动词当名词用了。后来重构时,直接回归到/users/{userId}/orders,简单明了。
URL设计:资源的外在表达
URL就是资源在网络上的“门牌号”。好的URL,看着地址就知道里面住的是谁。
我见过不少团队的URL设计,只能说……很有个性。比如:
GET /getUsers
POST /createUser
GET /userInfo/123
POST /updateUserData
DELETE /removeUserAccount
嗯,这里要注意,这些URL里都带了动词,这是典型的RPC风格。放在RESTful API里,不推荐这么做。为什么?因为HTTP方法本身就已经是动词了,你再把动词写到路径里,就重复了。
正确的做法是:用名词定义资源,用HTTP方法定义操作。
我的习惯:URL只包含名词和路径参数。动作统一交给 GET、POST、PUT、PATCH、DELETE 来表达。
来看个对比表:
| 动作 | 反模式(动词) | 推荐(名词 + HTTP方法) |
|---|---|---|
| 查询用户列表 | GET /getUsers | GET /users |
| 创建用户 | POST /createUser | POST /users |
| 查询单个用户 | GET /userInfo/{id} | GET /users/{id} |
| 删除用户 | GET /removeUser/{id} | DELETE /users/{id} |
命名规范:复数、短横线、全小写
聊完了结构,聊命名。我个人坚持三个原则:
- 使用复数名词:
/users而不是/user,/orders而不是/order。这样一眼看上去就知道是一个集合。 - 使用短横线(-)连接单词:
/user-profiles而不是/userProfiles或/user_profiles。短横线在URL里最友好,搜索引擎也认。 - 全部小写:
/system-configs而不是/SystemConfigs。大小写敏感很容易出bug,统一小写最省心。
我曾经因为URL里混用了驼峰和下划线,导致前端和后端排查了半天。从那以后,我就严格执行全小写短横线。事实证明,这个习惯让团队协作顺畅了很多。
路径参数与查询参数
在URL里怎么放数据?路径参数和查询参数各有各的职责。
| 参数类型 | 用途 | 示例 |
|---|---|---|
| 路径参数 | 标识特定资源或资源层级关系 | /users/{userId}/orders/{orderId} |
| 查询参数 | 过滤、排序、分页 | /users?role=admin&page=1 |
路径参数是“必需的”,它告诉你“我在操作哪个资源”。而查询参数是“可选的”,它告诉你“我只要符合什么条件的数据”。
这里有个容易踩的坑:千万别把查询参数当成路径参数来分层次。比如 /users?departmentId=123,这没问题。但如果你写成 /users/department/123,就会把部门当成用户资源的下一级,从语义上就不对了。部门是另一个资源,应该用 /departments/123/users。
我曾经遇到的坑:把复杂嵌套全部放到路径参数里,比如 /api/v1/tenants/{tenantId}/projects/{projectId}/tasks/{taskId}/comments/{commentId}。这种深度嵌套不仅让URL难以阅读,还容易导致性能瓶颈。后来我改为在查询参数中传递父资源的ID,或者通过资源的关系属性直接定位,简洁多了。
版本控制
API总有一天会变。怎么让旧客户端不崩?版本控制是必须的。
我常用的方式:在URL里放版本号。比如 /v1/users、/v2/users。这样改动对客户端的影响最小,也最直观。
也有人喜欢用 header 或媒体类型做版本控制。说实话,各有优劣。但如果你刚开始做API,建议用 URL 版本号,简单、直接、好调试。
还有个细节:版本号不要动不动就小版本写进URL。比如 /v1.1/users,没必要。版本号只在大改时递增,小改动向后兼容即可。
知识结构图
下面这张图,把资源建模和URL设计的关键逻辑串了起来。仔细看看,能帮你理清思路。
最后说两句
资源建模和URL设计,看起来是细节,实则是API整体质量的基石。很多API后面的各种问题,追根溯源,都能找到最初设计URL时留下的隐患。
我个人习惯,在写第一行代码之前,先把资源模型和URL列表画出来,跟团队成员过一遍。这一遍审核下去,能省下后面重构的大把时间。
另外,别小看了命名。一个直观的URL,比任何文档都管用。你想想看,看到 /v1/users,你就知道它是个用户资源的集合。看到 DELETE /v1/users/123,你就知道它是删除用户。清晰,自解释,这就是好设计。
嗯,这章的内容就到这里。下个话题,咱们聊路由与视图函数的解耦实践。