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简明教程

相关推荐
木雷坞4 小时前
Go 项目实战:用 MLiev IAM 落地企业认证中心
后端·golang·认证
Moment8 小时前
长上下文会最终杀死 Rag 吗?
前端·javascript·后端
蝎子莱莱爱打怪9 小时前
🚀 🚀🚀2026年5月GitHub月榜精选:17个项目中挑出10个推荐,实操4个!
人工智能·后端·ai编程
砍材农夫10 小时前
物联网实战:Spring Boot MQTT | MQTT 设备模拟器演示(附源码)
java·spring boot·后端·物联网·spring·netty
我叫黑大帅10 小时前
解决聊天页内部滚轮改为页面滚动问题
javascript·后端·面试
IT_陈寒11 小时前
Python的线程池居然把我坑在了垃圾回收这块
前端·人工智能·后端
zhangxingchao11 小时前
AI应用开发八:RAG相关技术总结
前端·人工智能·后端
吴佳浩11 小时前
Go史上最大“打脸”现场来了:泛型方法终于实现了
后端·go
Huyuejia12 小时前
runtime-ask
后端
Rust研习社12 小时前
90% 的 Rust 新手都不知道的 3 个实用开发技巧
后端·rust·编程语言