RESTful API 规范
核心原则
RESTful API 必须遵循 REST 架构风格,使用标准 HTTP 方法和状态码,确保 API 的可预测性和一致性。
允许的做法
URL 设计
- 使用 名词复数形式表示资源
- 使用 kebab-case(短横线)命名
- 使用 嵌套表示资源关系(不超过 2 层)
✅ 正确
GET /api/users # 获取用户列表
GET /api/users/{id} # 获取单个用户
GET /api/users/{id}/orders # 获取用户的订单
POST /api/products # 创建商品HTTP 方法
- 使用 标准 HTTP 方法表示操作
| 方法 | 用途 | 示例 |
|---|---|---|
| GET | 获取资源 | GET /api/users |
| POST | 创建资源 | POST /api/users |
| PUT | 完整更新资源 | PUT /api/users/ |
| PATCH | 部分更新资源 | PATCH /api/users/ |
| DELETE | 删除资源 | DELETE /api/users/ |
✅ 正确示例
# 用户管理
GET /api/users # 获取用户列表
POST /api/users # 创建用户
GET /api/users/{id} # 获取用户详情
PUT /api/users/{id} # 更新用户(全量)
PATCH /api/users/{id} # 更新用户(部分)
DELETE /api/users/{id} # 删除用户
# 商品管理
GET /api/products # 获取商品列表
POST /api/products # 创建商品
GET /api/products/{id} # 获取商品详情HTTP 状态码
- 使用 标准 HTTP 状态码
| 状态码 | 说明 | 使用场景 |
|---|---|---|
| 200 | OK | 成功获取/更新资源 |
| 201 | Created | 成功创建资源 |
| 204 | No Content | 成功删除资源 |
| 400 | Bad Request | 请求参数错误 |
| 401 | Unauthorized | 未认证 |
| 403 | Forbidden | 无权限 |
| 404 | Not Found | 资源不存在 |
| 500 | Internal Server Error | 服务器错误 |
go
// ✅ 正确 - Echo 框架示例
func GetUser(c echo.Context) error {
id := c.Param("id")
user, err := userService.GetByID(id)
if err != nil {
return c.JSON(http.StatusNotFound, response.Fail(404, "用户不存在"))
}
return c.JSON(http.StatusOK, response.Success(user))
}
func CreateUser(c echo.Context) error {
var req CreateUserRequest
if err := c.Bind(&req); err != nil {
return c.JSON(http.StatusBadRequest, response.Fail(400, "参数错误"))
}
user, err := userService.Create(&req)
if err != nil {
return c.JSON(http.StatusInternalServerError, response.Fail(500, "创建失败"))
}
return c.JSON(http.StatusCreated, response.Success(user))
}查询参数
- 使用 查询参数进行过滤、排序、分页
✅ 正确
# 分页
GET /api/users?page=1&pageSize=20
# 过滤
GET /api/products?status=active&category=electronics
# 排序
GET /api/users?sort=createdAt&order=desc
# 搜索
GET /api/users?q=alice
# 字段选择
GET /api/users?fields=id,name,email版本控制
- 使用 URL 路径版本控制
- 使用 v1, v2 格式
✅ 正确
GET /api/v1/users
GET /api/v2/users禁止的做法
禁止的 URL 设计
- 禁止 使用动词(除非是 RPC 风格的操作)
- 禁止 使用下划线
- 禁止 URL 结尾斜杠
❌ 错误
GET /api/getUsers # 使用动词
GET /api/user_list # 使用下划线
GET /api/users/ # 结尾斜杠
GET /api/users/1/orders/2/items/3 # 嵌套过深禁止的操作
- 禁止 使用 GET 方法修改数据
- 禁止 在 URL 中包含敏感信息
- 避免 返回不一致的数据结构
❌ 错误
GET /api/users/delete/{id} # GET 不应修改数据
GET /api/users?password=secret # URL 包含敏感信息RESTful API 设计示例
用户管理 API
# 用户列表(分页)
GET /api/v1/users?page=1&pageSize=20
Response: {
"success": true,
"data": [...],
"total": 100,
"current": 1,
"pageSize": 20
}
# 创建用户
POST /api/v1/users
Request: {
"name": "Alice",
"email": "alice@example.com"
}
Response: {
"success": true,
"data": {
"id": 123,
"name": "Alice",
"email": "alice@example.com"
}
}
# 获取用户详情
GET /api/v1/users/123
Response: {
"success": true,
"data": {
"id": 123,
"name": "Alice",
"email": "alice@example.com"
}
}
# 更新用户(部分)
PATCH /api/v1/users/123
Request: {
"name": "Alice Wang"
}
Response: {
"success": true,
"data": {
"id": 123,
"name": "Alice Wang",
"email": "alice@example.com"
}
}
# 删除用户
DELETE /api/v1/users/123
Response: {
"success": true
}资源关系 API
# 获取用户的订单
GET /api/v1/users/123/orders
# 获取订单详情(推荐使用独立端点)
GET /api/v1/orders/456
# 创建用户的订单
POST /api/v1/users/123/orders特殊操作
非 CRUD 操作
对于不符合 CRUD 的操作,使用 动词子资源:
✅ 正确
POST /api/v1/users/123/activate # 激活用户
POST /api/v1/orders/456/cancel # 取消订单
POST /api/v1/orders/456/refund # 退款
POST /api/v1/users/123/reset-password # 重置密码
POST /api/v1/documents/123/submit # 提交文档
POST /api/v1/tasks/456/assign # 分配任务
POST /api/v1/tasks/456/complete # 完成任务实现示例:
go
// ✅ 正确 - Echo 框架实现
func (h *TaskHandler) AssignTask(c echo.Context) error {
taskID := c.Param("id")
var req AssignTaskRequest
if err := c.Bind(&req); err != nil {
return c.JSON(http.StatusBadRequest, response.Fail(1000, "参数错误"))
}
err := h.taskService.Assign(c.Request().Context(), taskID, req.TranslatorID)
if err != nil {
return c.JSON(http.StatusInternalServerError, response.Fail(500, "分配失败"))
}
return c.JSON(http.StatusOK, response.Success(nil))
}批量操作
✅ 正确
POST /api/v1/users/batch-delete
Request: {
"ids": [1, 2, 3]
}
POST /api/v1/products/batch-update
Request: {
"ids": [1, 2, 3],
"status": "inactive"
}自定义操作最佳实践
原则 1:优先考虑标准 REST 方法
go
// ✅ 优先使用 PATCH 更新状态
PATCH /api/v1/orders/123
Request: { "status": "cancelled" }
// ⚠️ 仅在业务语义复杂时使用自定义操作
POST /api/v1/orders/123/cancel
Request: { "reason": "customer request", "refund": true }原则 2:自定义操作应使用 POST 方法
✅ 正确 - 使用 POST 执行操作
POST /api/v1/users/123/activate
POST /api/v1/orders/456/ship
❌ 错误 - 不要使用 GET执行修改操作
GET /api/v1/users/123/activate原则 3:操作名称使用动词
✅ 正确
POST /api/v1/tasks/123/submit
POST /api/v1/documents/123/approve
POST /api/v1/users/123/reset-password
❌ 错误
POST /api/v1/tasks/123/submission
POST /api/v1/documents/123/approval常见自定义操作场景
状态转换操作:
go
// 订单状态转换
POST /api/v1/orders/123/cancel // 取消订单
POST /api/v1/orders/123/ship // 发货
POST /api/v1/orders/123/complete // 完成订单
// 用户状态管理
POST /api/v1/users/123/activate // 激活
POST /api/v1/users/123/deactivate // 停用
POST /api/v1/users/123/lock // 锁定批准/审核操作:
go
POST /api/v1/documents/123/submit // 提交审核
POST /api/v1/documents/123/approve // 批准
POST /api/v1/documents/123/reject // 拒绝
Request: {
"comment": "审核意见"
}分配/转移操作:
go
POST /api/v1/tasks/123/assign // 分配任务
Request: {
"assigneeId": 456
}
POST /api/v1/tickets/123/transfer // 转移工单
Request: {
"targetUserId": 789,
"note": "转移原因"
}导出/生成操作:
go
POST /api/v1/reports/generate // 生成报告
Request: {
"startDate": "2025-01-01",
"endDate": "2025-01-31",
"format": "pdf"
}
Response: {
"success": true,
"data": {
"reportId": "abc123",
"downloadUrl": "https://cdn.example.com/reports/abc123.pdf"
}
}