请看下面这样一段代码
js
import express from 'express';
import cors from 'cors';
import { readFile, writeFile } from 'node:fs/promises';
const app = express();
app.use(cors());
app.use(express.json());
const port = process.env.PORT;
app.get('/todos', async (_req, res) => {
const todosData = await readFile('./data.json', 'utf-8');
const todos = JSON.parse(todosData);
// console.log(todos);
return res.status(200).json(todos);
});
app.get('/todos/:todoId', async (req, res) => {
const todosData = await readFile('./data.json', 'utf-8');
const todos = JSON.parse(todosData);
const todoId = req.params.todoId;
const todo = todos.find((todo) => todo.id === Number(todoId));
if (todo) {
return res.status(200).json(todo);
}
return res.status(404).send('404 Not Found');
});
// TODO: From get to delete
app.delete('/todos/:todoId', async (req, res) => {
const todosData = await readFile('./data.json', 'utf-8');
const todos = JSON.parse(todosData);
const todoId = req.params.todoId;
const filteredTodos = todos.filter((todo) => todo.id !== Number(todoId));
await writeFile('./data.json', JSON.stringify(filteredTodos), 'utf-8');
return res.status(200).json({
message: 'Todo deleted successfully',
});
});
// TODO: From get to post(A little trap here, be careful ^_^)
app.post('/todos', async (req, res) => {
const todosData = await readFile('./data.json', 'utf-8');
const todos = JSON.parse(todosData);
const addTodo = req.body;
const updatedTodos = [...todos, addTodo];
await writeFile('./data.json', JSON.stringify(updatedTodos), 'utf-8');
return res.status(200).json({
message: 'Todo added successfully',
});
});
// TODO: From get to patch
app.patch('/todos', async (req, res) => {
const todosData = await readFile('./data.json', 'utf-8');
const todos = JSON.parse(todosData);
const updateTodo = req.body;
const updatedTodos = todos.map((todo) => {
if (todo.id === updateTodo.id) {
return {
...todo,
...updateTodo,
};
}
return todo;
});
await writeFile('./data.json', JSON.stringify(updatedTodos), 'utf-8');
return res.status(200).json({
message: 'Todo updated successfully',
});
});
app.listen(port, () => {
console.log(`Example app listening on port http://localhost:${port}`);
});
所有的逻辑导入,全部都放在了server.js中。这样既不优雅也不美观。本节就带大家一起重构这样的代码。
- controllers:Business logic (handles requests/responses) 项目文件夹下,创建/src/controllers
controllers目录下存放所有的函数处理逻辑。以上述代码为例,就可以创建userControllers.js文件,将原代码中的
js
async (_req, res) => {
const todosData = await readFile('./data.json', 'utf-8');
const todos = JSON.parse(todosData);
return res.status(200).json(todos);
}
改造为:
js
export async function getTodos(_req, res) {
const todosData = await readFile("./data.json", "utf-8");
const todos = JSON.parse(todosData);
return res.status(200).json(todos);
}
同理,可以对其它函数做相同的操作
- 在src目录下创建routes目录,存放路由的逻辑
简单来说,就是将todoController中的逻辑和路由相互匹配:
js
const router = express.Router();
router.route("/todos").get(getTodos).post(postTodo).patch(patchTodo);
router.route("/todos/:todoId").get(getTodoById).delete(deleteTodoById);
export default router;
这里参照了express官方的写法,你同样可以选择稍显啰嗦的版本
3.在server.js使用路由
有了前两步,整个server.js就仅仅只需要一行代码:
js
app.use("", router);
聪明的你,一定会想到:如果后续需要进行版本更新,那么原来的路由就用不了了吗?有什么办法可以更好的进行版本控制呢? 其实很简单。
js
app.use("v1", router);
只需要在这里加上v1,后续的版本测试与更新,可以使用v2,等待稳定后将路由切换为v2即可
- 我们可以将server.js同样移动到src路径下。注意,此时记得更改package.json的scripts配置
js
"scripts": {
"dev": "dotenvx run -- nodemon ./src/server.js"
},
5.再次审阅我们的server.js代码。会发现里面有很多这样的代码(引入中间件),当后续项目庞大起来,放在server.js同样难以维护。我们在src下创建app.js,将相关逻辑集中在app.js中
js
import express from "express";
import cors from "cors";
import router from "./routes/todoRoutes.js";
const app = express();
app.use(cors());
app.use(express.json());
app.use("", router);
export default app;
这样server.js最终只有这么一点代码
js
import app from "./app.js";
const port = process.env.PORT;
app.listen(port, () => {
console.log(`Example app listening on port http://localhost:${port}`);
});
参考文章:Best Practices for Structuring an Express.js Project - DEV Community NodeJS简明教程