快速构建Express服务

JavaScript/前端
175
0
0
2024-05-28

使用Mongoose构建服务

该方式需要在本地安装MongoDB才可以

使用 TypeScript、Express、Mongoose 和 pnpm 可以快速构建后端服务,并实现增删改查以及列表查询的功能。下面是一个简单的示例:

首先,确保已经安装了 Node.js 和 pnpm。

创建项目文件夹,并进入该文件夹:

mkdir backend
cd backend

初始化 npm 项目,并选择 TypeScript 作为开发语言:

pnpm init

安装依赖:

pnpm install express mongoose
pnpm install --save-dev typescript ts-node nodemon @types/express @types/mongoose

创建 TypeScript 配置文件 tsconfig.json

{
  "compilerOptions": {
    "target": "es6",
    "module": "commonjs",
    "outDir": "dist",
    "strict": true,
    "esModuleInterop": true
  },
  "include": ["src"]
}

创建 src 文件夹,并在其中创建以下文件:

  • app.ts:Express 应用程序的入口文件。
  • models.ts:Mongoose 模型定义文件。
  • routes.ts:Express 路由定义文件。

models.ts 文件中定义 Mongoose 模型。例如,我们创建一个 User 模型:

import mongoose from 'mongoose';

const userSchema = new mongoose.Schema({
  name: {
    type: String,
    required: true
  },
  age: {
    type: Number,
    required: true
  }
});

export default mongoose.model('User', userSchema);

routes.ts 文件中定义 Express 路由。例如,我们创建一个处理用户相关操作的路由:

import express, { Request, Response, NextFunction }  from 'express';
import User from './models';

const router = express.Router();

// 获取用户列表
router.get('/users', async (req, res) => {
  try {
    const users = await User.find();
    res.json(users);
  } catch (error:any) {
    res.status(500).json({ message: error.message });
  }
});

// 创建用户
router.post('/users', async (req, res) => {
  const { name, age } = req.body;
  const user = new User({ name, age });

  try {
    const newUser = await user.save();
    res.status(201).json(newUser);
  } catch (error:any) {
    res.status(400).json({ message: error.message });
  }
});

// 获取单个用户
router.get('/users/:id', getUser, (req, res:any) => {
  res.json(res.user);
});

// 更新用户
router.patch('/users/:id', getUser, async (req, res:any) => {
  const { name, age } = req.body;

  if (name) {
    res.user.name = name;
  }

  if (age) {
    res.user.age = age;
  }

  try {
    const updatedUser = await res.user.save();
    res.json(updatedUser);
  } catch (error:any) {
    res.status(400).json({ message: error.message });
  }
});

// 删除用户
router.delete('/users/:id', getUser, async (req, res:any) => {
  try {
    await res.user.remove();
    res.json({ message: 'User deleted' });
  } catch (error:any) {
    res.status(500).json({ message: error.message });
  }
});

async function getUser(req: Request, res: any, next: NextFunction) {
  let user;

  try {
    user = await User.findById(req.params.id);

    if (user == null) {
      return res.status(404).json({ message: 'User not found' });
    }
  } catch (error:any) {
    return res.status(500).json({ message: error.message });
  }

  res.user = user;
  next();
}

export default router;

app.ts 文件中创建 Express 应用程序,并配置中间件和路由:

import express from 'express';
import mongoose from 'mongoose';
import routes from './routes';

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

app.use(express.json());
app.use(routes);

mongoose.connect('mongodb://localhost:27017/mydatabase', {
  useNewUrlParser: true,
  useUnifiedTopology: true
}).then(() => {
  console.log('Connected to MongoDB');
}).catch((error) => {
  console.error('Error connecting to MongoDB:', error.message);
});

app.listen(port, () => {
  console.log(`Server running on port ${port}`);
});

package.json 文件中添加脚本命令:

{
  "scripts": {
    "start": "nodemon --exec ts-node src/app.ts"
  }
}

启动应用程序:

pnpm start

现在,你的后端服务已经启动,可以使用 Postman 或其他工具测试 API。以下是一些示例请求:

接口测试

  • 获取用户列表:GET http://localhost:3000/users
  • 创建用户:POST http://localhost:3000/users,请求体为 JSON 格式的用户数据。
  • 获取单个用户:GET http://localhost:3000/users/{id}
  • 更新用户:PATCH http://localhost:3000/users/{id},请求体为 JSON 格式的更新数据。
  • 删除用户:DELETE http://localhost:3000/users/{id}

请注意,这只是一个简单的示例,实际项目中可能需要更多的验证、错误处理和安全性措施。

使用内存数据库SQLite数据库

该方式无需安装数据库SQLite,使用的是内存数据库

以下步骤和之前的一样,不再做过多解释

mkdir backend
cd backend

pnpm init

pnpm install express
pnpm install --save-dev typescript ts-node nodemon @types/express

安装SQLLite数据库

npm install sqlite3 sequelize
pnpm install @types/body-parser
models.ts
import { Sequelize, DataTypes, Model } from 'sequelize';

export interface TodoListAttributes {
  id?: number;
  title: string;
  desc: string;
}

export class TodoList extends Model<TodoListAttributes> implements TodoListAttributes {
  public id!: number;
  public title!: string;
  public desc!: string;

  public readonly createdAt!: Date;
  public readonly updatedAt!: Date;
}

export const sequelize = new Sequelize({
  dialect: 'sqlite',
  storage: ':memory:'
});

TodoList.init(
  {
    title: {
      type: DataTypes.STRING,
      allowNull: false
    },
    desc: {
      type: DataTypes.STRING,
      allowNull: false
    }
  },
  {
    sequelize,
    modelName: 'TodoList'
  }
);
controllers.ts
import { Request, Response } from 'express';
import { TodoList } from '../model/models';

export const createTodoList = async (req: Request, res: Response) => {
  try {
    const { title, desc } = req.body;
    const todoList = await TodoList.create({ title, desc });
    res.status(201).json(todoList.toJSON());
  } catch (error) {
    console.error('Error creating todoList:', error);
    res.status(500).json({ error: 'Internal server error' });
  }
};

export const getTodoList = async (req: Request, res: Response) => {
  try {
    const todoLists = await TodoList.findAll();
    res.json(todoLists.map(todoList => todoList.toJSON()));
  } catch (error) {
    console.error('Error getting todoLists:', error);
    res.status(500).json({ error: 'Internal server error' });
  }
};

export const getTodoListById = async (req: Request, res: Response) => {
  try {
    const { id } = req.params;
    const todoList = await TodoList.findByPk(id);
    if (todoList) {
      res.json(todoList.toJSON());
    } else {
      res.status(404).json({ error: 'TodoList not found' });
    }
  } catch (error) {
    console.error('Error getting todoList by ID:', error);
    res.status(500).json({ error: 'Internal server error' });
  }
};

export const updateTodoList = async (req: Request, res: Response) => {
  try {
    const { id } = req.params;
    const { title, desc } = req.body;
    const todoList = await TodoList.findByPk(id);
    if (todoList) {
      await todoList.update({ title, desc });
      res.json(todoList.toJSON());
    } else {
      res.status(404).json({ error: 'TodoList not found' });
    }
  } catch (error) {
    console.error('Error updating todoList:', error);
    res.status(500).json({ error: 'Internal server error' });
  }
};

export const deleteTodoList = async (req: Request, res: Response) => {
  try {
    const { id } = req.params;
    const todoList = await TodoList.findByPk(id);
    if (todoList) {
      await todoList.destroy();
      res.json({ message: 'TodoList deleted successfully' });
    } else {
      res.status(404).json({ error: 'TodoList not found' });
    }
  } catch (error) {
    console.error('Error deleting todoList:', error);
    res.status(500).json({ error: 'Internal server error' });
  }
};
routes.ts
import express from 'express';
import { createTodoList, getTodoList, getTodoListById, updateTodoList, deleteTodoList } from '../utils/controllers';

const router = express.Router();

router.post('/todo-list', createTodoList);
router.get('/todo-list', getTodoList);
router.get('/todo-list/:id', getTodoListById);
router.put('/todo-list/:id', updateTodoList);
router.delete('/todo-list/:id', deleteTodoList);

export default router;

app.ts

import express from 'express';
import bodyParser from 'body-parser';
import { sequelize } from './model/models';
import router from './router/router';

const app = express();

app.use(bodyParser.json());
app.use(router);

const startServer = async () => {
  try {
    await sequelize.sync();
    app.listen(3000, () => {
      console.log('Server is running on port 3000');
    });
  } catch (error) {
    console.error('Error starting server:', error);
  }
};

startServer();

启动

pnpm start

接口测试

  • 获取列表:GET localhost:3000/todo-list
  • 创建:POST localhost:3000/todo-list,请求体为 JSON 格式的数据。
  • 获取单个数据:GET localhost:3000/todo-list/1
  • 更新数据:PUT localhost:3000/todo-list/2,请求体为 JSON 格式的更新数据。
  • 删除数据:DELETE localhost:3000/todo-list/2

源码

todo-express.zip

好了,本章节到此告一段落。希望对你有所帮助,祝学习顺利。