03 RESTful API 设计规范 - 设计优雅的接口
🎯 本章目标:理解RESTful架构风格,掌握URL设计规范、HTTP方法语义,学会阅读和测试RESTful接口。
3.1 什么是RESTful
生活中的类比
想象一个图书馆管理系统:
传统方式(非RESTful):
/getUserInfo?id=1 → 获取用户信息
/createUser → 创建用户
/updateUser → 更新用户
/deleteUser?id=1 → 删除用户
RESTful方式:
GET /users/1 → 获取用户信息
POST /users → 创建用户
PUT /users/1 → 更新用户
DELETE /users/1 → 删除用户
RESTful的核心思想:用URL定位资源,用HTTP方法描述对资源的操作。
REST的定义
REST(Representational State Transfer,表现层状态转换) 是一种软件架构风格,由Roy Fielding在2000年提出。
- 资源 Resources:URL表示
- 表现层 Representation:JSON/XML
- 状态转换 State Transfer:HTTP方法
- 无状态 Stateless:每次请求独立
3.2 RESTful设计六大原则
原则1:URL表示资源,不是动作
| 错误(动词在URL中) | 正确(名词表示资源) |
|---|---|
GET /getUser?id=1 |
GET /users/1 |
POST /createUser |
POST /users |
POST /updateUser |
PUT /users/1 |
GET /deleteUser?id=1 |
DELETE /users/1 |
原则2:用HTTP方法表示操作
| HTTP方法 | 操作 | 幂等性 | 示例 |
|---|---|---|---|
| GET | 读取资源 | 是 | GET /users 获取用户列表 |
| POST | 创建资源 | 否 | POST /users 创建新用户 |
| PUT | 全量更新 | 是 | PUT /users/1 替换用户1的全部信息 |
| PATCH | 部分更新 | 否 | PATCH /users/1 只更新用户1的邮箱 |
| DELETE | 删除资源 | 是 | DELETE /users/1 删除用户1 |
原则3:使用复数名词
/users ✓ 正确
/user ✗ 错误(用复数)
/Users ✗ 错误(小写)
/getUsers ✗ 错误(不要有动词)
原则4:正确的HTTP状态码
- 成功 → 返回 2xx(200 OK, 201 Created, 204 No Content)
- 客户端错误 → 返回 4xx(400, 401, 403, 404, 422)
- 服务端错误 → 返回 5xx(500, 502, 503)
原则5:使用查询参数过滤、排序、分页
GET /users?role=admin&sort=name&page=1&size=20
↑ ↑ ↑ ↑
过滤条件 排序字段 页码 每页数量
原则6:版本控制
/api/v1/users → API版本1
/api/v2/users → API版本2
或放在Header中:
Accept: application/vnd.api.v1+json
3.3 RESTful URL设计实战
电商系统接口设计
| 功能 | HTTP方法 | URL | 说明 |
|---|---|---|---|
| 用户模块 | |||
| 获取用户列表 | GET | /api/v1/users |
支持分页、筛选 |
| 获取单个用户 | GET | /api/v1/users/1 |
用户ID为1 |
| 创建用户 | POST | /api/v1/users |
Body传用户数据 |
| 更新用户 | PUT | /api/v1/users/1 |
全量更新 |
| 部分更新 | PATCH | /api/v1/users/1 |
部分字段更新 |
| 删除用户 | DELETE | /api/v1/users/1 |
软删除或硬删除 |
| 获取用户订单 | GET | /api/v1/users/1/orders |
嵌套资源 |
| 商品模块 | |||
| 获取商品列表 | GET | /api/v1/products |
支持分类筛选 |
| 获取商品详情 | GET | /api/v1/products/100 |
商品ID为100 |
| 搜索商品 | GET | /api/v1/products?keyword=手机 |
关键词搜索 |
| 订单模块 | |||
| 创建订单 | POST | /api/v1/orders |
从购物车创建 |
| 获取订单 | GET | /api/v1/orders/2024001 |
订单号 |
| 取消订单 | PUT | /api/v1/orders/2024001/status |
更新状态 |
| 获取订单商品 | GET | /api/v1/orders/2024001/items |
订单明细 |
3.4 请求和响应的数据格式
标准响应结构
json
{
"code": 0,
"message": "success",
"data": {
"id": 1,
"name": "张三",
"email": "zhangsan@example.com"
}
}
分页响应结构
json
{
"code": 0,
"message": "success",
"data": {
"list": [
{"id": 1, "name": "张三"},
{"id": 2, "name": "李四"}
],
"pagination": {
"page": 1,
"size": 20,
"total": 100,
"totalPages": 5
}
}
}
错误响应结构
json
{
"code": 1001,
"message": "用户名或密码错误",
"data": null,
"details": {
"field": "password",
"reason": "密码长度不足"
}
}
3.5 RESTful API测试要点
测试维度
- URL规范:是否使用复数名词、是否无动词、嵌套资源是否合理
- HTTP方法:GET只读、POST创建、PUT/PATCH更新、DELETE删除
- 状态码:2xx成功、4xx客户端错误、5xx服务端错误
- 响应格式:统一结构、错误信息清晰、分页信息完整
测试检查清单
| 检查项 | 说明 | 通过标准 |
|---|---|---|
| URL设计 | 是否使用名词复数 | /users ✓ /getUsers ✗ |
| HTTP方法 | 方法是否语义正确 | GET获取、POST创建、PUT更新、DELETE删除 |
| 状态码 | 返回码是否合理 | 创建返回201、删除返回204 |
| 响应格式 | 结构是否统一 | 包含code、message、data |
| 错误处理 | 错误信息是否友好 | 包含错误码和详细说明 |
| 分页 | 分页参数是否支持 | page、size、total |
| 过滤排序 | 查询参数是否支持 | ?role=admin&sort=name |
| 版本控制 | API是否有版本 | /api/v1/... |
3.6 实战:分析一个RESTful接口文档
接口文档示例
yaml
# 用户管理接口
## 获取用户列表
GET /api/v1/users
请求参数:
page: 页码 (默认1)
size: 每页数量 (默认20)
role: 角色筛选 (可选)
响应:
200 OK
{
"code": 0,
"data": {
"list": [...],
"pagination": {...}
}
}
## 获取单个用户
GET /api/v1/users/{id}
路径参数:
id: 用户ID
响应:
200 OK - 用户存在
404 Not Found - 用户不存在
## 创建用户
POST /api/v1/users
请求体:
{
"name": "张三",
"email": "zhangsan@example.com",
"role": "user"
}
响应:
201 Created
{
"code": 0,
"data": {"id": 1, "name": "张三", ...}
}
400 Bad Request - 参数错误
409 Conflict - 邮箱已存在
## 更新用户
PUT /api/v1/users/{id}
请求体:
{
"name": "张三",
"email": "zhangsan@example.com",
"role": "admin"
}
响应:
200 OK
404 Not Found
## 删除用户
DELETE /api/v1/users/{id}
响应:
204 No Content
404 Not Found
测试用例设计
- GET /users:正常分页、带筛选条件、边界值(page=0)
- GET /users/1:存在的用户、不存在的用户、非法ID(abc)
- POST /users:正常创建、缺少必填字段、邮箱格式错误、重复邮箱
- PUT /users/1:正常更新、更新不存在的用户、非法字段值
- DELETE /users/1:正常删除、删除不存在的用户、无权限删除
3.7 非RESTful接口怎么办
现实情况
不是所有接口都是纯RESTful的,常见变体:
- 纯RESTful:严格遵循6原则
- 类RESTful:大部分RESTful,少量自定义
- RPC风格HTTP:全用POST,URL含动作
- GraphQL:单一端点,查询语言
类RESTful示例
POST /api/v1/users/1/enable → 启用用户(自定义动作)
POST /api/v1/users/1/disable → 禁用用户(自定义动作)
POST /api/v1/orders/1/refund → 订单退款(自定义动作)
测试策略:理解设计意图,按实际规范测试,不必强求纯RESTful。
3.8 本章小结
RESTful核心要点
- URL设计:名词复数、无动词、嵌套资源
- HTTP方法:GET读 POST建 PUT PATCH更新 DELETE删
- 状态码:201创建 204删除 404不存在
- 响应格式:统一结构、错误清晰、分页完整
课后练习 📝
- 设计题:为一个博客系统设计RESTful API,包含文章、评论、标签、用户四个模块。
- 分析题:分析你工作中或常用的API,判断是否符合RESTful规范,有哪些可以改进的地方。
- 测试题:针对上面的用户管理接口文档,写出至少10个测试用例(包含正常和异常场景)。
3.9 下章预告
下一章我们将学习常见接口类型和数据格式(JSON、XML、GraphQL等),以及如何在接口测试中使用它们!
"RESTful不是教条,而是一种优雅的设计哲学。理解它,你就能设计出让人愉悦的API。"