3-12:路由和重构

请看下面这样一段代码

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中。这样既不优雅也不美观。本节就带大家一起重构这样的代码。

  1. 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);
}

同理,可以对其它函数做相同的操作

  1. 在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即可

  1. 我们可以将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简明教程

相关推荐
掘金者阿豪2 小时前
我用 Codex Rule 模式“驯服AI写代码”:从翻车到稳定上线的完整实践(附企业级规则模板 + 架构图)
后端
鱼人2 小时前
现代C++启示录:告别裸指针,你的代码里还有很多“C的幽灵”
后端
cylgdzz1112 小时前
DSP技术架构深度拆解
后端·架构
imuliuliang2 小时前
Spring Boot 多数据源解决方案:dynamic-datasource-spring-boot-starter 的奥秘(上)
java·spring boot·后端
霸道流氓气质2 小时前
SpringBoot+LangChain4j+Ollama实现Function Calling工具调用-仿智能客服示例
java·spring boot·后端
Rust研习社3 小时前
深入浅出 Rust 泛型:从入门到实战
开发语言·后端·算法·rust
许彰午3 小时前
源码全开放,没人看——一个框架作者的真实经历
java·后端
YGY顾n凡3 小时前
我开源了一个项目:一句话创造一个AI世界!
前端·后端·aigc
SamDeepThinking3 小时前
写了十几年代码,聊聊什么样的人能做好Java开发
java·后端·程序员