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