RESTful API 设计
这页适合作为“面向团队协作的 API 设计基线”。真正好的 API,不只是能返回数据,而是命名稳定、错误可读、分页一致、版本演进可控,前后端和第三方调用者都能长期接得住。
推荐设计顺序
设计 API 时,建议按下面顺序思考:
- 先明确资源模型与 URL 命名
- 再统一响应格式、错误格式、状态码语义
- 然后补认证、权限、限流与幂等性
- 最后处理版本控制、文档与测试
如果一开始就只关注“接口能不能调通”,后面最容易出问题的往往是命名混乱和兼容性失控。
URL 设计
# 资源用名词复数
GET /api/users # 获取用户列表
GET /api/users/123 # 获取单个用户
POST /api/users # 创建用户
PUT /api/users/123 # 更新用户(全量)
PATCH /api/users/123 # 更新用户(部分)
DELETE /api/users/123 # 删除用户
# 嵌套资源
GET /api/users/123/posts # 用户的文章
POST /api/users/123/posts # 为用户创建文章
# 查询参数
GET /api/users?page=1&limit=20&sort=-created_at
GET /api/users?search=domi&role=admin
HTTP 状态码
| 状态码 | 含义 | 使用场景 |
|---|---|---|
| 200 | OK | 成功 |
| 201 | Created | 创建成功 |
| 204 | No Content | 删除成功 |
| 400 | Bad Request | 请求参数错误 |
| 401 | Unauthorized | 未认证 |
| 403 | Forbidden | 无权限 |
| 404 | Not Found | 资源不存在 |
| 409 | Conflict | 资源冲突 |
| 422 | Unprocessable Entity | 验证失败 |
| 429 | Too Many Requests | 限流 |
| 500 | Internal Server Error | 服务器错误 |
响应格式
成功响应
{
"data": {
"id": 123,
"name": "Domi",
"email": "[email]"
}
}
列表响应(分页)
{
"data": [...],
"meta": {
"page": 1,
"limit": 20,
"total": 100,
"totalPages": 5
}
}
错误响应
{
"error": {
"code": "VALIDATION_ERROR",
"message": "请求参数验证失败",
"details": [{ "field": "email", "message": "邮箱格式不正确" }]
}
}
分页、筛选、排序建议
这类规则一旦定下来,最好全站统一:
GET /api/users?page=1&limit=20
GET /api/users?sort=-created_at
GET /api/users?search=domi&role=admin
建议:
page/limit用于传统分页sort=-created_at用-表示倒序,风格直观- 筛选字段尽量与资源属性同名,避免同一概念多套叫法
如果系统以后会有大列表、高频翻页或无限加载,也可以尽早评估 cursor pagination。
认证方案
JWT(JSON Web Token)
Authorization: Bearer eyJhbGciOiJIUzI1NiIs...
// 生成
import jwt from "jsonwebtoken";
const token = jwt.sign({ userId: 123, role: "admin" }, process.env.JWT_SECRET, {
expiresIn: "7d",
});
// 验证
const payload = jwt.verify(token, process.env.JWT_SECRET);
API Key
# Header
X-API-Key: sk-xxxxxxxxxxxx
# 或查询参数
GET /api/data?api_key=sk-xxxxxxxxxxxx
版本控制
# URL 路径(推荐)
/api/v1/users
/api/v2/users
# Header
Accept: application/vnd.myapi.v2+json
幂等与写操作建议
写接口时,除了成功与失败,还要考虑“重复请求会怎样”:
GET、PUT、DELETE天然更适合设计成幂等POST创建资源时,如果客户端可能重试,最好考虑幂等键或业务去重- 支付、回调、任务创建这类接口,尤其要避免重复提交造成脏数据
限流
响应头中返回限流信息:
X-RateLimit-Limit: 100
X-RateLimit-Remaining: 95
X-RateLimit-Reset: 1709020800
CORS
// Express
app.use(
cors({
origin: ["https://example.com"],
methods: ["GET", "POST", "PUT", "DELETE"],
credentials: true,
}),
);
文档工具
| 工具 | 说明 |
|---|---|
| Swagger/OpenAPI | API 规范标准 |
| Scalar | 现代 API 文档 |
| Bruno | 开源 API 客户端 |
| Hoppscotch | 在线 API 测试 |
常见问题
URL 和资源命名不统一
例如一会儿叫 /users,一会儿叫 /user-list,一会儿又是 /getUsers。这会让前端、文档、测试、SDK 都越来越难维护。资源 URL 尽量保持名词化和稳定。
状态码都返回 200
这会让调用方很难区分真成功和业务失败。即使接口里有 success: false,也不应该完全放弃 HTTP 状态码语义。
错误结构每个接口都不一样
一旦错误结构不统一,前端就只能写大量特判。建议把 code、message、details 这类字段尽量统一下来。
延伸阅读
参考链接
- HTTP API Design Guide — 设计指南
- REST API Tutorial — 教程
- OpenAPI 规范 — 官方规范