创建一个任务管理 API

在本教程中,我们将使用 Node.js 和 Express.js 框架来创建一个简单的任务管理 API。这个 API 将允许用户创建、读取、更新和删除任务。我们将涵盖从环境搭建到 API 设计和实现的整个过程。

1. 环境搭建

1.1 安装 Node.js 和 npm

首先,确保你已经安装了 Node.js 和 npm。你可以通过以下命令检查它们的版本:

node -v
npm -v

如果没有安装,你可以从 Node.js 官网 下载并安装。

1.2 使用 nvm 管理 Node.js 版本

为了方便管理 Node.js 版本,建议安装 nvm(Node Version Manager)。你可以通过以下命令安装 nvm:

curl -o- https://raw.githubusercontent.com/nvm-sh/nvm/v0.39.1/install.sh | bash

安装完成后,你可以使用以下命令安装和切换 Node.js 版本:

nvm install 14
nvm use 14

2. 创建第一个 Node.js 应用

2.1 初始化项目

创建一个新的项目目录并初始化 npm:

mkdir task-manager-api
cd task-manager-api
npm init -y

2.2 安装 Express.js

Express.js 是一个流行的 Node.js 框架,用于构建 Web 应用程序和 API。我们可以通过以下命令安装它:

npm install express

2.3 创建第一个 Express 应用

在项目根目录下创建一个 index.js 文件,并添加以下代码:

const express = require('express');
const app = express();
const port = 3000;

app.get('/', (req, res) => {
  res.send('Hello, Task Manager API!');
});

app.listen(port, () => {
  console.log(`Server is running on http://localhost:${port}`);
});

运行应用:

node index.js

打开浏览器并访问 http://localhost:3000,你应该会看到 "Hello, Task Manager API!" 的消息。

3. 模块系统

3.1 CommonJS 模块

在 Node.js 中,默认使用 CommonJS 模块系统。你可以通过 require 和 module.exports 来导入和导出模块。

例如,创建一个 utils.js 文件:

// utils.js
function add(a, b) {
  return a + b;
}

module.exports = { add };

然后在 index.js 中使用它:

const { add } = require('./utils');

console.log(add(2, 3)); // 输出 5

3.2 ES Modules

从 Node.js 12 开始,你可以使用 ES Modules。你可以在 package.json 中添加 "type": "module",然后使用 import 和 export 语法。

例如,修改 utils.js:

// utils.js
export function add(a, b) {
  return a + b;
}

然后在 index.js 中使用它:

import { add } from './utils.js';

console.log(add(2, 3)); // 输出 5

4. 包管理器

4.1 npm

npm 是 Node.js 的默认包管理器。你可以使用 npm install 安装依赖,使用 npm start 运行脚本。

4.2 yarn

yarn 是另一个流行的包管理器,它提供了更快的安装速度和更好的依赖管理。你可以通过以下命令安装 yarn:

npm install -g yarn

然后使用 yarn add 安装依赖,使用 yarn start 运行脚本。

5. 事件循环和异步编程

5.1 事件循环

Node.js 是单线程的,但它通过事件循环来处理异步操作。事件循环允许 Node.js 执行非阻塞 I/O 操作。

5.2 异步编程

Node.js 提供了多种异步编程方式:

  • 回调函数:传统的异步编程方式。
  • Promise:更现代的异步编程方式。
  • async/await:基于 Promise 的语法糖,使异步代码看起来像同步代码。

例如,使用 setTimeout 模拟异步操作:

function delay(ms) {
  return new Promise(resolve => setTimeout(resolve, ms));
}

async function asyncFunction() {
  console.log('Start');
  await delay(2000);
  console.log('End');
}

asyncFunction();

6. 流和缓冲区

6.1 流

流是 Node.js 中处理大文件或数据流的机制。流可以是可读的、可写的或双工的。

例如,使用 fs 模块创建一个可读流:

const fs = require('fs');
const readStream = fs.createReadStream('file.txt');

readStream.on('data', (chunk) => {
  console.log(`Received ${chunk.length} bytes of data.`);
});

readStream.on('end', () => {
  console.log('Finished reading file.');
});

6.2 缓冲区

缓冲区是 Node.js 中处理二进制数据的机制。你可以使用 Buffer 类来创建和操作缓冲区。

例如,创建一个缓冲区并写入数据:

const buffer = Buffer.from('Hello, Node.js!');
console.log(buffer.toString()); // 输出 "Hello, Node.js!"

7. 文件系统操作

7.1 读取文件

使用 fs 模块读取文件:

const fs = require('fs');

fs.readFile('file.txt', 'utf8', (err, data) => {
  if (err) throw err;
  console.log(data);
});

7.2 写入文件

使用 fs 模块写入文件:

const fs = require('fs');

fs.writeFile('file.txt', 'Hello, Node.js!', (err) => {
  if (err) throw err;
  console.log('File written successfully.');
});

8. 网络编程

8.1 HTTP 模块

Node.js 提供了 http 模块来创建 HTTP 服务器和客户端。

例如,创建一个简单的 HTTP 服务器:

const http = require('http');

const server = http.createServer((req, res) => {
  res.statusCode = 200;
  res.setHeader('Content-Type', 'text/plain');
  res.end('Hello, World!\n');
});

server.listen(3000, () => {
  console.log('Server running at http://localhost:3000/');
});

8.2 HTTPS 模块

Node.js 还提供了 https 模块来创建 HTTPS 服务器。你需要提供 SSL 证书和密钥。

9. Express.js 框架入门

9.1 安装 Express.js

我们已经在前面的步骤中安装了 Express.js。

9.2 创建一个简单的 Express 应用

修改 index.js 文件:

const express = require('express');
const app = express();
const port = 3000;

app.get('/', (req, res) => {
  res.send('Hello, Task Manager API!');
});

app.listen(port, () => {
  console.log(`Server is running on http://localhost:${port}`);
});

10. 路由和中间件

10.1 路由

路由是定义如何响应客户端请求的机制。你可以使用 app.get、app.post 等方法来定义路由。

例如,定义一个 /tasks 路由:

app.get('/tasks', (req, res) => {
  res.send('List of tasks');
});

10.2 中间件

中间件是处理请求和响应的函数。你可以使用 app.use 来添加中间件。

例如,添加一个日志中间件:

app.use((req, res, next) => {
  console.log(`${req.method} ${req.url}`);
  next();
});

11. 模板引擎

11.1 EJS

EJS 是一个简单的模板引擎,允许你在 HTML 中嵌入 JavaScript 代码。

安装 EJS:

npm install ejs

配置 EJS:

app.set('view engine', 'ejs');

创建一个 views 目录,并在其中创建一个 index.ejs 文件:

<!DOCTYPE html>
<html>
<head>
  <title>Task Manager</title>
</head>
<body>
  <h1>Tasks</h1>
  <ul>
    <% tasks.forEach(task => { %>
      <li><%= task %></li>
    <% }) %>
  </ul>
</body>
</html>

在 index.js 中渲染模板:

app.get('/tasks', (req, res) => {
  const tasks = ['Task 1', 'Task 2', 'Task 3'];
  res.render('index', { tasks });
});

11.2 Pug

Pug 是另一个流行的模板引擎,使用缩进来定义 HTML 结构。

安装 Pug:

npm install pug

配置 Pug:

app.set('view engine', 'pug');

创建一个 views 目录,并在其中创建一个 index.pug 文件:

doctype html
html
  head
    title Task Manager
  body
    h1 Tasks
    ul
      each task in tasks
        li= task

在 index.js 中渲染模板:

app.get('/tasks', (req, res) => {
  const tasks = ['Task 1', 'Task 2', 'Task 3'];
  res.render('index', { tasks });
});

12. RESTful API 设计和实现

12.1 设计 RESTful API

RESTful API 遵循 REST 架构风格,使用 HTTP 方法(GET、POST、PUT、DELETE)来操作资源。

例如,设计一个任务管理 API:

  • GET /tasks:获取所有任务
  • GET /tasks/:id:获取单个任务
  • POST /tasks:创建新任务
  • PUT /tasks/:id:更新任务
  • DELETE /tasks/:id:删除任务

12.2 实现 RESTful API

使用 Express.js 实现上述 API:

let tasks = [];
let taskId = 1;

app.use(express.json());

app.get('/tasks', (req, res) => {
  res.json(tasks);
});

app.get('/tasks/:id', (req, res) => {
  const task = tasks.find(t => t.id === parseInt(req.params.id));
  if (!task) return res.status(404).send('Task not found');
  res.json(task);
});

app.post('/tasks', (req, res) => {
  const task = { id: taskId++, ...req.body };
  tasks.push(task);
  res.status(201).json(task);
});

app.put('/tasks/:id', (req, res) => {
  const task = tasks.find(t => t.id === parseInt(req.params.id));
  if (!task) return res.status(404).send('Task not found');
  task.title = req.body.title;
  task.completed = req.body.completed;
  res.json(task);
});

app.delete('/tasks/:id', (req, res) => {
  tasks = tasks.filter(t => t.id !== parseInt(req.params.id));
  res.status(204).send();
});

13. 身份认证和授权

13.1 基本认证

使用 Express.js 实现基本认证:

app.use((req, res, next) => {
  const auth = { login: 'admin', password: 'password' };
  const b64auth = (req.headers.authorization || '').split(' ')[1] || '';
  const [login, password] = Buffer.from(b64auth, 'base64').toString().split(':');

  if (login && password && login === auth.login && password === auth.password) {
    return next();
  }

  res.set('WWW-Authenticate', 'Basic realm="401"');
  res.status(401).send('Authentication required.');
});

13.2 JWT 认证

使用 JSON Web Token (JWT) 实现认证:

安装 jsonwebtoken:

npm install jsonwebtoken

实现 JWT 认证:

const jwt = require('jsonwebtoken');
const secretKey = 'your-secret-key';

app.post('/login', (req, res) => {
  const { username, password } = req.body;
  if (username === 'admin' && password === 'password') {
    const token = jwt.sign({ username }, secretKey, { expiresIn: '1h' });
    res.json({ token });
  } else {
    res.status(401).send('Invalid credentials');
  }
});

app.use((req, res, next) => {
  const token = req.headers['authorization'];
  if (!token) return res.status(403).send('Token required');

  jwt.verify(token, secretKey, (err, decoded) => {
    if (err) return res.status(401).send('Invalid token');
    req.user = decoded;
    next();
  });
});

14. SQL 数据库

14.1 MySQL

安装 mysql2 包:

npm install mysql2

连接到 MySQL 数据库:

const mysql = require('mysql2');

const connection = mysql.createConnection({
  host: 'localhost',
  user: 'root',
  password: 'password',
  database: 'task_manager'
});

connection.connect((err) => {
  if (err) throw err;
  console.log('Connected to MySQL database');
});

14.2 PostgreSQL

安装 pg 包:

npm install pg

连接到 PostgreSQL 数据库:

const { Client } = require('pg');

const client = new Client({
  user: 'root',
  host: 'localhost',
  database: 'task_manager',
  password: 'password',
  port: 5432,
});

client.connect((err) => {
  if (err) throw err;
  console.log('Connected to PostgreSQL database');
});

15. NoSQL 数据库

15.1 MongoDB

安装 mongodb 包:

npm install mongodb

连接到 MongoDB 数据库:

const { MongoClient } = require('mongodb');

const uri = 'mongodb://localhost:27017';
const client = new MongoClient(uri, { useNewUrlParser: true, useUnifiedTopology: true });

client.connect((err) => {
  if (err) throw err;
  console.log('Connected to MongoDB database');
});

16. ORM 和 ODM

16.1 Sequelize

Sequelize 是一个流行的 ORM,支持多种 SQL 数据库。

安装 Sequelize 和 MySQL 驱动:

npm install sequelize mysql2

初始化 Sequelize:

const { Sequelize } = require('sequelize');

const sequelize = new Sequelize('task_manager', '