Express教程 - 第三部分:RESTful API设计

RESTful API 是一种基于 HTTP 协议设计的 API 规范,其核心是通过统一的接口风格实现客户端与服务器之间的资源交互。它并非强制标准,而是一种 “设计哲学”,旨在让 API 更简洁、可扩展、易于理解和维护。

RESTful API 是一种 “设计规范”,而 Express 是实现这种规范的 “高效工具”。Express 凭借其路由系统、中间件机制和对 HTTP 特性的封装,为开发者提供了简洁的方式来构建符合 RESTful 规范的 API。

一、核心关系:规范与实现工具

  • RESTful API:是一套设计接口的 “思想和规则”(如以资源为中心、用 HTTP 方法表达操作、用状态码表示结果等),本身不依赖任何技术栈。
  • Express:是 Node.js 生态中的 Web 框架,它通过封装 HTTP 模块、提供路由和中间件等功能,降低了遵循 RESTful 规范的开发成本,让开发者能更专注于业务逻辑而非底层细节。

简单说:RESTful 定义了 “API 应该长什么样”,Express 提供了 “快速造出这种 API 的工具”。

二、Express 如何支撑 RESTful API 的实现?

Express 的核心特性与 RESTful 规范高度契合,具体体现在以下几个方面:

1. 路由系统:精准匹配 “资源 URI + HTTP 方法”

RESTful 要求用 URI 标识资源,用 HTTP 方法表达对资源的操作(如 GET /users 表示获取用户列表)。Express 的路由系统天然支持这种映射:

  • HTTP 方法绑定:Express 提供了 app.get()app.post()app.put()app.delete() 等方法,直接对应 RESTful 规范中 GET(查)、POST(增)、PUT(全量改)、DELETE(删)等操作,语义清晰。

    示例:

    // 符合 RESTful 的路由设计
    app.get('/users', (req, res) => { /* 获取所有用户(查)*/ });
    app.get('/users/:id', (req, res) => { /* 获取单个用户(查)*/ });
    app.post('/users', (req, res) => { /* 创建用户(增)*/ });
    app.put('/users/:id', (req, res) => { /* 全量更新用户(改)*/ });
    app.delete('/users/:id', (req, res) => { /* 删除用户(删)*/ });
    
  • 动态路由参数:RESTful 中用 URI 路径标识单个资源(如 /users/123),Express 通过 :param 语法支持动态参数(req.params.id),轻松获取资源标识。

2. 中间件:解决 RESTful 所需的共性问题

RESTful API 开发中需要处理的认证、权限校验、请求体解析、错误处理等共性逻辑,可通过 Express 中间件高效实现:

  • 请求体解析:RESTful 中创建 / 更新资源时需传递数据(如 POST 请求体),Express 内置的 express.json() 或第三方中间件(如 body-parser)可直接解析 JSON 或表单数据到 req.body,简化参数获取。

    示例:

    const express = require('express');
    const app = express();
    app.use(express.json()); // 解析 JSON 格式的请求体
    
    app.post('/users', (req, res) => {
      const newUser = req.body; // 直接获取请求体数据(符合 RESTful 新增资源的参数传递方式)
      // 保存用户逻辑...
      res.status(201).json(newUser); // 用 201 状态码表示创建成功(符合 RESTful 状态码规范)
    });
    
  • 认证与权限:通过自定义中间件验证用户身份(如 JWT 验证),确保只有授权用户能操作资源,符合 RESTful 对资源访问控制的需求。

    示例:

    // 认证中间件
    const auth = (req, res, next) => {
      const token = req.headers.authorization;
      if (!token) return res.status(401).json({ error: '未认证' }); // 401 符合 RESTful 状态码
      // 验证 token 逻辑...
      next(); // 验证通过,进入下一个中间件/路由处理函数
    };
    
    // 保护路由:只有认证用户能访问
    app.get('/users', auth, (req, res) => { /* 获取用户列表 */ });
    
  • 错误处理:Express 的错误处理中间件(参数为 (err, req, res, next))可统一捕获异常,并返回符合 RESTful 规范的错误响应(如 404、500 状态码 + 错误信息)。

3. 响应处理:贴合 RESTful 对 “资源表示” 的要求

RESTful 要求服务器返回资源的 “表示”(如 JSON),并通过 HTTP 状态码和头信息传递元数据。Express 对 res 对象的扩展完美支持这一点:

  • 资源表示res.json() 方法可直接返回 JSON 格式的资源数据(RESTful 最常用的表示格式)。
  • 状态码控制res.status(code) 可灵活设置状态码(如 201 表示创建成功、404 表示资源不存在),符合 RESTful 对状态码的规范。
  • 资源定位:创建资源后,可通过 res.location(uri) 设置响应头 Location,返回新资源的 URI(如 res.location('/users/123').status(201).json(...))。
4. 模块化路由:适配 RESTful 的资源分类

RESTful 中不同资源(如用户、订单、商品)的接口应分离管理,Express的 express.Router() 支持路由模块化,可按资源拆分代码,保持项目结构清晰:

示例:

// routes/users.js(用户资源路由模块)
const express = require('express');
const router = express.Router();

router.get('/', (req, res) => { /* 获取所有用户 */ });
router.post('/', (req, res) => { /* 创建用户 */ });
// ...其他用户相关接口

module.exports = router;

// app.js(主应用)
const userRouter = require('./routes/users');
app.use('/users', userRouter); // 挂载用户路由,所有接口自动带上 /users 前缀

三、RESTful API示例教程

1. 创建RESTful API基础教程

advanced\01-restful-api-basics.js

// 高级教程1: RESTful API设计基础
const express = require('express');
const app = express();
const PORT = 3007;

// 中间件配置
app.use(express.json());
app.use(express.urlencoded({ extended: true }));

console.log('🌐 RESTful API设计教程');
console.log('================================');

// 模拟数据库(内存存储)
let users = [
    { id: 1, name: '张三', email: 'zhangsan@example.com', age: 25 },
    { id: 2, name: '李四', email: 'lisi@example.com', age: 30 },
    { id: 3, name: '王五', email: 'wangwu@example.com', age: 28 }
];

let nextId = 4;

// 🎯 第一部分:什么是RESTful API?
app.get('/api/intro', (req, res) => {
    res.json({
        title: 'RESTful API设计原则',
        principles: [
            {
                principle: '统一接口 (Uniform Interface)',
                description: '使用标准的HTTP方法和状态码',
                example: 'GET /users, POST /users, PUT /users/1'
            },
            {
                principle: '无状态 (Stateless)',
                description: '每个请求都包含所有必要信息',
                example: '不使用session,使用token认证'
            },
            {
                principle: '资源导向 (Resource-Based)',
                description: '一切皆资源,使用名词而不是动词',
                example: '/users 而不是 /getUsers'
            },
            {
                principle: '可缓存 (Cacheable)',
                description: '响应应该标明是否可缓存',
                example: '使用Cache-Control头'
            }
        ]
    });
});

// 🎯 第二部分:HTTP方法详解
app.get('/api/http-methods', (req, res) => {
    res.json({
        methods: [
            {
                method: 'GET',
                purpose: '获取资源',
                example: 'GET /api/users - 获取用户列表',
                idempotent: true,
                safe: true
            },
            {
                method: 'POST',
                purpose: '创建新资源',
                example: 'POST /api/users - 创建新用户',
                idempotent: false,
                safe: false
            },
            {
                method: 'PUT',
                purpose: '更新整个资源',
                example: 'PUT /api/users/1 - 更新用户1的所有信息',
                idempotent: true,
                safe: false
            },
            {
                method: 'PATCH',
                purpose: '部分更新资源',
                example: 'PATCH /api/users/1 - 只更新用户1的部分信息',
                idempotent: false,
                safe: false
            },
            {
                method: 'DELETE',
                purpose: '删除资源',
                example: 'DELETE /api/users/1 - 删除用户1',
                idempotent: true,
                safe: false
            }
        ]
    });
});

// 🎯 第三部分:完整的用户API实现
// 1. 获取所有用户 (GET /api/users)
app.get('/api/users', (req, res) => {
    console.log('📋 获取用户列表');
    
    // 分页参数
    const page = parseInt(req.query.page) || 1;
    const limit = parseInt(req.query.limit) || 10;
    const startIndex = (page - 1) * limit;
    const endIndex = startIndex + limit;
    
    // 过滤参数
    const nameFilter = req.query.name;
    
    let filteredUsers = users;
    if (nameFilter) {
        filteredUsers = users.filter(user => 
            user.name.toLowerCase().includes(nameFilter.toLowerCase())
        );
    }
    
    // 分页结果
    const paginatedUsers = filteredUsers.slice(startIndex, endIndex);
    
    res.json({
        success: true,
        data: paginatedUsers,
        pagination: {
            currentPage: page,
            totalPages: Math.ceil(filteredUsers.length / limit),
            totalItems: filteredUsers.length,
            hasNext: endIndex < filteredUsers.length,
            hasPrev: page > 1
        },
        filters: {
            name: nameFilter || '无'
        }
    });
});

// 2. 获取单个用户 (GET /api/users/:id)
app.get('/api/users/:id', (req, res) => {
    const userId = parseInt(req.params.id);
    const user = users.find(u => u.id === userId);
    
    if (!user) {
        return res.status(404).json({
            success: false,
            message: '用户不存在',
            errorCode: 'USER_NOT_FOUND'
        });
    }
    
    console.log(`👤 获取用户详情: ${user.name}`);
    res.json({
        success: true,
        data: user
    });
});

// 3. 创建新用户 (POST /api/users)
app.post('/api/users', (req, res) => {
    console.log('➕ 创建新用户');
    
    const { name, email, age } = req.body;
    
    // 数据验证
    if (!name || !email) {
        return res.status(400).json({
            success: false,
            message: '姓名和邮箱是必填项',
            errorCode: 'VALIDATION_ERROR'
        });
    }
    
    // 检查邮箱是否已存在
    const existingUser = users.find(u => u.email === email);
    if (existingUser) {
        return res.status(409).json({
            success: false,
            message: '邮箱已存在',
            errorCode: 'EMAIL_EXISTS'
        });
    }
    
    const newUser = {
        id: nextId++,
        name,
        email,
        age: age || null,
        createdAt: new Date().toISOString()
    };
    
    users.push(newUser);
    
    res.status(201).json({
        success: true,
        message: '用户创建成功',
        data: newUser
    });
});

// 4. 更新用户信息 (PUT /api/users/:id)
app.put('/api/users/:id', (req, res) => {
    const userId = parseInt(req.params.id);
    const userIndex = users.findIndex(u => u.id === userId);
    
    if (userIndex === -1) {
        return res.status(404).json({
            success: false,
            message: '用户不存在',
            errorCode: 'USER_NOT_FOUND'
        });
    }
    
    const { name, email, age } = req.body;
    
    // 数据验证
    if (!name || !email) {
        return res.status(400).json({
            success: false,
            message: '姓名和邮箱是必填项',
            errorCode: 'VALIDATION_ERROR'
        });
    }
    
    // 检查邮箱是否被其他用户使用
    const emailUser = users.find(u => u.email === email && u.id !== userId);
    if (emailUser) {
        return res.status(409).json({
            success: false,
            message: '邮箱已被其他用户使用',
            errorCode: 'EMAIL_IN_USE'
        });
    }
    
    users[userIndex] = {
        ...users[userIndex],
        name,
        email,
        age: age || null,
        updatedAt: new Date().toISOString()
    };
    
    console.log(`✏️ 更新用户: ${users[userIndex].name}`);
    res.json({
        success: true,
        message: '用户更新成功',
        data: users[userIndex]
    });
});

// 5. 删除用户 (DELETE /api/users/:id)
app.delete('/api/users/:id', (req, res) => {
    const userId = parseInt(req.params.id);
    const userIndex = users.findIndex(u => u.id === userId);
    
    if (userIndex === -1) {
        return res.status(404).json({
            success: false,
            message: '用户不存在',
            errorCode: 'USER_NOT_FOUND'
        });
    }
    
    const deletedUser = users.splice(userIndex, 1)[0];
    
    console.log(`🗑️ 删除用户: ${deletedUser.name}`);
    res.json({
        success: true,
        message: '用户删除成功',
        data: deletedUser
    });
});

// 🎯 第四部分:高级功能 - 搜索和统计
app.get('/api/users/search/:keyword', (req, res) => {
    const keyword = req.params.keyword.toLowerCase();
    const results = users.filter(user => 
        user.name.toLowerCase().includes(keyword) ||
        user.email.toLowerCase().includes(keyword)
    );
    
    res.json({
        success: true,
        keyword: keyword,
        results: results,
        count: results.length
    });
});

app.get('/api/stats', (req, res) => {
    const stats = {
        totalUsers: users.length,
        averageAge: users.reduce((sum, user) => sum + (user.age || 0), 0) / users.filter(u => u.age).length,
        createdToday: users.filter(u => {
            const today = new Date().toDateString();
            const userDate = new Date(u.createdAt || new Date()).toDateString();
            return today === userDate;
        }).length
    };
    
    res.json({
        success: true,
        data: stats
    });
});

// 错误处理中间件
app.use((err, req, res, next) => {
    console.error('❌ API错误:', err);
    res.status(500).json({
        success: false,
        message: '服务器内部错误',
        errorCode: 'INTERNAL_ERROR'
    });
});

// 404处理
app.use('/api/*', (req, res) => {
    res.status(404).json({
        success: false,
        message: 'API接口不存在',
        errorCode: 'ENDPOINT_NOT_FOUND'
    });
});

app.listen(PORT, () => {
    console.log(`🚀 RESTful API教程运行在 http://localhost:${PORT}`);
    console.log('');
    console.log('📚 学习端点:');
    console.log('  GET  /api/intro         - RESTful原则介绍');
    console.log('  GET  /api/http-methods   - HTTP方法详解');
    console.log('');
    console.log('🔧 实践端点:');
    console.log('  GET    /api/users        - 获取用户列表');
    console.log('  GET    /api/users/1      - 获取用户详情');
    console.log('  POST   /api/users        - 创建新用户');
    console.log('  PUT    /api/users/1      - 更新用户信息');
    console.log('  DELETE /api/users/1      - 删除用户');
    console.log('  GET    /api/stats        - 统计信息');
    console.log('');
    console.log('💡 使用Postman或curl测试这些API端点');
});

2. 创建API测试指南

API_TEST_GUIDE.md

# RESTful API测试指南

## 🧪 测试工具推荐

### 1. Postman(图形界面,推荐新手)
- 下载地址:https://www.postman.com/downloads/
- 优点:可视化操作,容易上手

### 2. curl(命令行工具)
- 系统自带,无需安装
- 优点:快速测试,适合自动化

## 🔍 API端点测试示例

### 获取所有用户
```bash
# curl命令
curl http://localhost:3007/api/users

# 带分页参数
curl "http://localhost:3007/api/users?page=1&limit=5"

# 带过滤参数
curl "http://localhost:3007/api/users?name=张三"
```

### 获取单个用户
```bash
curl http://localhost:3007/api/users/1
```

### 创建新用户
```bash
curl -X POST http://localhost:3007/api/users \
  -H "Content-Type: application/json" \
  -d '{"name":"赵六","email":"zhaoliu@example.com","age":35}'
```

### 更新用户信息
```bash
curl -X PUT http://localhost:3007/api/users/1 \
  -H "Content-Type: application/json" \
  -d '{"name":"张三丰","email":"zhangsanfeng@example.com","age":40}'
```

### 删除用户
```bash
curl -X DELETE http://localhost:3007/api/users/1
```

## 📊 HTTP状态码说明

| 状态码 | 含义 | 示例 |
|--------|------|------|
| 200 | 成功 | GET、PUT、DELETE操作成功 |
| 201 | 创建成功 | POST创建新资源 |
| 400 | 请求错误 | 数据验证失败 |
| 404 | 资源不存在 | 用户ID不存在 |
| 409 | 冲突 | 邮箱已存在 |
| 500 | 服务器错误 | 代码bug |

## 🎯 最佳实践

### 请求头设置
```bash
# 设置Content-Type
-H "Content-Type: application/json"

# 设置认证令牌
-H "Authorization: Bearer your-token-here"
```

### 响应格式统一
所有API返回统一格式:
```json
{
    "success": true/false,
    "message": "操作结果描述",
    "data": { /* 实际数据 */ },
    "errorCode": "错误代码(可选)"
}
```

### 错误处理
- 客户端错误(4xx):用户输入问题
- 服务器错误(5xx):代码bug或系统问题

3. 创建RESTful设计原则详解

advanced\02-restful-principles.js
// 高级教程2: RESTful设计原则详解
const express = require('express');
const app = express();
const PORT = 3008;

app.use(express.json());

console.log('📖 RESTful设计原则详解');
console.log('================================');

// 🎯 原则1:资源命名规范
app.get('/api/principles/naming', (req, res) => {
    res.json({
        title: '资源命名规范',
        rules: [
            {
                rule: '使用名词而不是动词',
                good: '/users',
                bad: '/getUsers'
            },
            {
                rule: '使用复数形式',
                good: '/users',
                bad: '/user'
            },
            {
                rule: '使用连字符而不是下划线',
                good: '/user-profiles',
                bad: '/user_profiles'
            },
            {
                rule: '避免大写字母',
                good: '/user-profiles',
                bad: '/UserProfiles'
            }
        ]
    });
});

// 🎯 原则2:HTTP方法正确使用
app.get('/api/principles/methods', (req, res) => {
    res.json({
        title: 'HTTP方法使用规范',
        examples: [
            {
                operation: '获取资源列表',
                method: 'GET',
                url: '/api/users',
                description: '获取所有用户'
            },
            {
                operation: '获取单个资源',
                method: 'GET', 
                url: '/api/users/123',
                description: '获取ID为123的用户'
            },
            {
                operation: '创建新资源',
                method: 'POST',
                url: '/api/users',
                description: '创建新用户'
            },
            {
                operation: '更新整个资源',
                method: 'PUT',
                url: '/api/users/123', 
                description: '完全更新用户123的信息'
            },
            {
                operation: '部分更新资源',
                method: 'PATCH',
                url: '/api/users/123',
                description: '只更新用户123的部分信息'
            },
            {
                operation: '删除资源',
                method: 'DELETE',
                url: '/api/users/123',
                description: '删除用户123'
            }
        ]
    });
});

// 🎯 原则3:状态码正确使用
app.get('/api/principles/status-codes', (req, res) => {
    res.json({
        title: 'HTTP状态码使用规范',
        codes: [
            {
                code: 200,
                meaning: 'OK - 请求成功',
                usage: 'GET、PUT、DELETE操作成功'
            },
            {
                code: 201,
                meaning: 'Created - 创建成功', 
                usage: 'POST创建新资源成功'
            },
            {
                code: 204,
                meaning: 'No Content - 无内容',
                usage: 'DELETE成功,但不需要返回内容'
            },
            {
                code: 400,
                meaning: 'Bad Request - 请求错误',
                usage: '客户端数据验证失败'
            },
            {
                code: 401,
                meaning: 'Unauthorized - 未授权',
                usage: '需要登录认证'
            },
            {
                code: 403,
                meaning: 'Forbidden - 禁止访问',
                usage: '有权限但被拒绝'
            },
            {
                code: 404,
                meaning: 'Not Found - 资源不存在',
                usage: '请求的资源不存在'
            },
            {
                code: 409,
                meaning: 'Conflict - 冲突',
                usage: '资源状态冲突(如邮箱已存在)'
            },
            {
                code: 500,
                meaning: 'Internal Server Error - 服务器错误',
                usage: '服务器端代码错误'
            }
        ]
    });
});

app.listen(PORT, () => {
    console.log(`📚 RESTful原则教程运行在 http://localhost:${PORT}`);
    console.log('访问以下端点学习设计原则:');
    console.log('  /api/principles/naming     - 资源命名规范');
    console.log('  /api/principles/methods    - HTTP方法规范');
    console.log('  /api/principles/status-codes - 状态码规范');
});

4. 创建学习实践项目

examples\02-todo-api.js

// 实践案例2: Todo列表API
const express = require('express');
const app = express();
const PORT = 3009;

app.use(express.json());

console.log('✅ Todo列表API实践项目');
console.log('================================');

// 模拟数据库
let todos = [
    { id: 1, title: '学习Express', completed: false, createdAt: new Date() },
    { id: 2, title: '练习RESTful API', completed: true, createdAt: new Date() },
    { id: 3, title: '构建Todo应用', completed: false, createdAt: new Date() }
];

let nextId = 4;

// 🎯 完整的Todo API实现
// GET /api/todos - 获取所有待办事项
app.get('/api/todos', (req, res) => {
    const { completed, search } = req.query;
    
    let filteredTodos = todos;
    
    // 过滤完成状态
    if (completed !== undefined) {
        const isCompleted = completed === 'true';
        filteredTodos = filteredTodos.filter(todo => todo.completed === isCompleted);
    }
    
    // 搜索功能
    if (search) {
        filteredTodos = filteredTodos.filter(todo => 
            todo.title.toLowerCase().includes(search.toLowerCase())
        );
    }
    
    res.json({
        success: true,
        data: filteredTodos,
        total: filteredTodos.length,
        completed: filteredTodos.filter(t => t.completed).length,
        pending: filteredTodos.filter(t => !t.completed).length
    });
});

// GET /api/todos/:id - 获取单个待办事项
app.get('/api/todos/:id', (req, res) => {
    const todo = todos.find(t => t.id === parseInt(req.params.id));
    
    if (!todo) {
        return res.status(404).json({
            success: false,
            message: '待办事项不存在'
        });
    }
    
    res.json({ success: true, data: todo });
});

// POST /api/todos - 创建新待办事项
app.post('/api/todos', (req, res) => {
    const { title } = req.body;
    
    if (!title || title.trim() === '') {
        return res.status(400).json({
            success: false,
            message: '标题不能为空'
        });
    }
    
    const newTodo = {
        id: nextId++,
        title: title.trim(),
        completed: false,
        createdAt: new Date()
    };
    
    todos.push(newTodo);
    
    res.status(201).json({
        success: true,
        message: '待办事项创建成功',
        data: newTodo
    });
});

// PUT /api/todos/:id - 更新待办事项
app.put('/api/todos/:id', (req, res) => {
    const todoIndex = todos.findIndex(t => t.id === parseInt(req.params.id));
    
    if (todoIndex === -1) {
        return res.status(404).json({
            success: false,
            message: '待办事项不存在'
        });
    }
    
    const { title, completed } = req.body;
    
    if (title !== undefined && title.trim() === '') {
        return res.status(400).json({
            success: false,
            message: '标题不能为空'
        });
    }
    
    todos[todoIndex] = {
        ...todos[todoIndex],
        title: title !== undefined ? title.trim() : todos[todoIndex].title,
        completed: completed !== undefined ? completed : todos[todoIndex].completed,
        updatedAt: new Date()
    };
    
    res.json({
        success: true,
        message: '待办事项更新成功',
        data: todos[todoIndex]
    });
});

// DELETE /api/todos/:id - 删除待办事项
app.delete('/api/todos/:id', (req, res) => {
    const todoIndex = todos.findIndex(t => t.id === parseInt(req.params.id));
    
    if (todoIndex === -1) {
        return res.status(404).json({
            success: false,
            message: '待办事项不存在'
        });
    }
    
    const deletedTodo = todos.splice(todoIndex, 1)[0];
    
    res.json({
        success: true,
        message: '待办事项删除成功',
        data: deletedTodo
    });
});

// 🎯 批量操作
// PATCH /api/todos/batch-complete - 批量完成
app.patch('/api/todos/batch-complete', (req, res) => {
    const { ids } = req.body;
    
    if (!Array.isArray(ids)) {
        return res.status(400).json({
            success: false,
            message: 'ids必须是数组'
        });
    }
    
    let updatedCount = 0;
    todos.forEach(todo => {
        if (ids.includes(todo.id)) {
            todo.completed = true;
            todo.updatedAt = new Date();
            updatedCount++;
        }
    });
    
    res.json({
        success: true,
        message: `批量完成了 ${updatedCount} 个待办事项`
    });
});

// GET /api/todos/stats - 统计信息
app.get('/api/todos/stats', (req, res) => {
    const stats = {
        total: todos.length,
        completed: todos.filter(t => t.completed).length,
        pending: todos.filter(t => !t.completed).length,
        completionRate: (todos.filter(t => t.completed).length / todos.length * 100).toFixed(1)
    };
    
    res.json({ success: true, data: stats });
});

app.listen(PORT, () => {
    console.log(`🚀 Todo API运行在 http://localhost:${PORT}`);
    console.log('');
    console.log('📋 可用端点:');
    console.log('  GET    /api/todos                 - 获取所有待办事项');
    console.log('  GET    /api/todos/:id             - 获取单个待办事项');
    console.log('  POST   /api/todos                 - 创建新待办事项');
    console.log('  PUT    /api/todos/:id             - 更新待办事项');
    console.log('  DELETE /api/todos/:id             - 删除待办事项');
    console.log('  PATCH  /api/todos/batch-complete  - 批量完成');
    console.log('  GET    /api/todos/stats           - 统计信息');
    console.log('');
    console.log('💡 使用Postman测试这些API,构建完整的前后端应用!');
});

🚀 现在开始学习RESTful API!

第一步:运行基础教程

node advanced/01-restful-api-basics.js

第二步:学习设计原则

node advanced/02-restful-principles.js

第三步:实践项目

node examples/02-todo-api.js

第四步:使用Postman测试

  1. 下载并安装Postman
  2. 测试所有API端点
  3. 观察请求和响应格式

学习重点:

  • 理解RESTful原则:资源导向、统一接口
  • 掌握HTTP方法:GET、POST、PUT、DELETE的正确使用
  • 学会状态码:正确返回HTTP状态码
  • 实践API设计:从需求到实现的完整流程

完成这部分后,你将能够设计出专业的Web API!


🐳Express框架就先整理这么多,就到这里,就到这里🐳

Logo

有“AI”的1024 = 2048,欢迎大家加入2048 AI社区

更多推荐