API设计 #
一、RESTful原则 #
1.1 REST架构风格 #
REST(Representational State Transfer)是一种软件架构风格,基于HTTP协议进行通信。
1.2 RESTful设计原则 #
| 原则 | 说明 |
|---|---|
| 统一接口 | 使用标准HTTP方法 |
| 无状态 | 请求包含所有信息 |
| 可缓存 | 响应可被缓存 |
| 分层系统 | 客户端无需知道后端结构 |
1.3 HTTP方法映射 #
| HTTP方法 | CRUD操作 | 说明 |
|---|---|---|
| GET | Read | 获取资源 |
| POST | Create | 创建资源 |
| PUT | Update | 完整更新 |
| PATCH | Update | 部分更新 |
| DELETE | Delete | 删除资源 |
二、URL设计 #
2.1 资源命名 #
使用名词复数形式:
text
GET /users 获取用户列表
GET /users/:id 获取单个用户
POST /users 创建用户
PUT /users/:id 更新用户
DELETE /users/:id 删除用户
2.2 嵌套资源 #
text
GET /users/:id/posts 用户的文章列表
GET /users/:id/posts/:postId 用户的某篇文章
POST /users/:id/posts 为用户创建文章
2.3 过滤和排序 #
text
GET /users?role=admin&status=active
GET /users?sort=createdAt:desc
GET /users?page=1&limit=10
GET /users?fields=id,name,email
2.4 动作资源 #
对于非CRUD操作:
text
POST /users/:id/activate
POST /orders/:id/cancel
POST /files/:id/download
三、响应格式 #
3.1 成功响应 #
单个资源:
json
{
"success": true,
"data": {
"id": 1,
"name": "张三",
"email": "zhangsan@example.com"
}
}
资源列表:
json
{
"success": true,
"data": [
{ "id": 1, "name": "张三" },
{ "id": 2, "name": "李四" }
],
"pagination": {
"page": 1,
"limit": 10,
"total": 100,
"totalPages": 10
}
}
3.2 错误响应 #
json
{
"success": false,
"error": {
"code": "VALIDATION_ERROR",
"message": "验证失败",
"details": [
{ "field": "email", "message": "请输入有效的邮箱地址" }
]
}
}
3.3 HTTP状态码 #
| 状态码 | 说明 | 使用场景 |
|---|---|---|
| 200 | 成功 | GET, PUT, PATCH |
| 201 | 创建成功 | POST |
| 204 | 无内容 | DELETE |
| 400 | 错误请求 | 参数验证失败 |
| 401 | 未认证 | 需要登录 |
| 403 | 禁止访问 | 无权限 |
| 404 | 未找到 | 资源不存在 |
| 409 | 冲突 | 资源已存在 |
| 422 | 无法处理 | 验证失败 |
| 500 | 服务器错误 | 程序错误 |
四、版本控制 #
4.1 URL版本 #
javascript
app.use('/api/v1', v1Routes);
app.use('/api/v2', v2Routes);
4.2 Header版本 #
javascript
app.use('/api', (req, res, next) => {
req.apiVersion = req.headers['accept-version'] || 'v1';
next();
});
4.3 查询参数版本 #
javascript
app.use('/api', (req, res, next) => {
req.apiVersion = req.query.version || 'v1';
next();
});
五、分页设计 #
5.1 偏移分页 #
text
GET /users?page=1&limit=10
javascript
const getPaginatedUsers = async (page, limit) => {
const skip = (page - 1) * limit;
const [users, total] = await Promise.all([
User.find().skip(skip).limit(limit),
User.countDocuments()
]);
return {
data: users,
pagination: {
page,
limit,
total,
totalPages: Math.ceil(total / limit),
hasNext: page < Math.ceil(total / limit),
hasPrev: page > 1
}
};
};
5.2 游标分页 #
text
GET /users?cursor=abc123&limit=10
javascript
const getCursorUsers = async (cursor, limit) => {
const query = cursor ? { _id: { $gt: cursor } } : {};
const users = await User.find(query)
.sort({ _id: 1 })
.limit(limit + 1);
const hasMore = users.length > limit;
if (hasMore) users.pop();
return {
data: users,
pagination: {
nextCursor: hasMore ? users[users.length - 1]._id : null,
hasMore
}
};
};
六、过滤和搜索 #
6.1 基本过滤 #
javascript
const buildQuery = (filters) => {
const query = {};
if (filters.status) {
query.status = filters.status;
}
if (filters.role) {
query.role = filters.role;
}
if (filters.minAge || filters.maxAge) {
query.age = {};
if (filters.minAge) query.age.$gte = filters.minAge;
if (filters.maxAge) query.age.$lte = filters.maxAge;
}
return query;
};
6.2 全文搜索 #
javascript
const searchUsers = async (q) => {
return await User.find({
$or: [
{ name: { $regex: q, $options: 'i' } },
{ email: { $regex: q, $options: 'i' } }
]
});
};
七、HATEOAS #
7.1 超媒体链接 #
json
{
"data": {
"id": 1,
"name": "张三"
},
"links": {
"self": "/api/users/1",
"posts": "/api/users/1/posts",
"avatar": "/api/users/1/avatar"
}
}
7.2 实现 #
javascript
const addUserLinks = (user) => {
return {
...user.toObject(),
links: {
self: `/api/users/${user._id}`,
posts: `/api/users/${user._id}/posts`
}
};
};
app.get('/users/:id', async (req, res) => {
const user = await User.findById(req.params.id);
res.json({ data: addUserLinks(user) });
});
八、API文档 #
8.1 Swagger/OpenAPI #
bash
npm install swagger-jsdoc swagger-ui-express
javascript
const swaggerJsdoc = require('swagger-jsdoc');
const swaggerUi = require('swagger-ui-express');
const options = {
definition: {
openapi: '3.0.0',
info: {
title: 'API文档',
version: '1.0.0'
}
},
apis: ['./routes/*.js']
};
const specs = swaggerJsdoc(options);
app.use('/api-docs', swaggerUi.serve, swaggerUi.setup(specs));
8.2 路由注释 #
javascript
/**
* @swagger
* /users:
* get:
* summary: 获取用户列表
* tags: [Users]
* parameters:
* - in: query
* name: page
* schema:
* type: integer
* responses:
* 200:
* description: 成功
*/
router.get('/users', getUsers);
九、总结 #
API设计要点:
| 概念 | 说明 |
|---|---|
| RESTful | 资源+HTTP方法 |
| URL设计 | 名词复数,层级清晰 |
| 响应格式 | 统一的成功/错误格式 |
| 版本控制 | URL/Header/查询参数 |
| 分页 | 偏移分页/游标分页 |
| 文档 | Swagger/OpenAPI |
下一步,让我们学习性能优化!
最后更新:2026-03-28