0%

使用 Mongoose + Express 创建基于 MongoDB的API接口服务

摘要:实现一套基于 nodejs + Mongoose + Express 的 API 接口服务,实现对后端 MongoDB 数据库的增删改查(CRUD)

架构原理

各部分功能

1、MongoDB ,一款流行的 NOSQL 文档数据库,用于数据的存储。

2、Nodejs,一款 javascript 运行环境,提供 NPM 等包管理工具。

3、Express,一款 WEB 框架,用于接收和发送 HTTP 请求,在 Nodejs 环境运行。

4、Mongoose,一款 MongoDB 驱动引擎,可以与数据库进行通信交互,在 Nodejs 环境运行。

可选:nodemon,实现在保存工程文件后,自动重启服务。

流程原理

1、在 Nodejs 环境当中,使用 Mongoose 连接 MongoDB 数据库;

2、数据库连接成功后,启动 Express 框架服务;

3、通过定义的 Express 路由与 Mongoose 模型,与 MongoDB 数据库通信;

4、通过 API 接口进行数据增删改查;

环境配置

说明:以下操作均基于 M1 芯片 MacBook Pro

(1)安装 MongoDB

详见:Install MongoDB — MongoDB Manual

(2)安装 Nodejs

详见:下载 | Node.js 中文网

(3)安装 Express 、Mongoose、nodemon

1
npm install express mongoose nodemon

创建项目

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
//创建目录
mkdir mongo-api

//进入目录
cd mongo-api

//初始化 nodejs
npm init -y

//查看当前目录文件,应包含 package.json
ls

//安装 Express 、Mongoose、nodemon
npm install express mongoose nodemon

//查看当前目录文件,应包含 node_modules
ls

//使用vscode打开当前目录(需提前配置 vscode)
code .

搭建基本 HTTP 访问服务

(1)创建 Express 访问入口文件 /app.js

1
2
3
4
5
6
7
8
9
10
11
12
13
// 引入工具包
const express = require("express");

//创建实例
const app = express();

//设定监听端口
const port = 3000;

//启动服务
app.listen(port, "127.0.0.1", (req, res) => {
console.log(`服务启动,运行在: http://127.0.0.1:${port} `);
});

(2) 修改 package.json 添加启动脚本命令

1
2
3
4
5
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1",
"start": "nodemon app.js" //这一行是新增的
},

(3)启动服务

1
2
3
4
5
npm start

//终端将自动打印日志:
[nodemon] starting `node app.js`
服务启动,运行在: http://127.0.0.1:3000

此时使用浏览器访问:http://127.0.0.1:3000 ,将显示:Cannot GET /(原因是还没定义处理函数)

搭建 MongoDB 基础访问服务

(1)在 /app.js主入口文件 ,引入 Mongoose 包并配置连接

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
// 引入工具包
const express = require("express");
const mongoose = require("mongoose");

// 连接MongoDB数据库,并在成功回调时,启动http服务
mongoose
.connect("mongodb://127.0.0.1:27017/mydb")
.then(() => {
//创建实例
const app = express();
//设定监听端口
const port = 3000;
//启动服务
app.listen(port, "127.0.0.1", (req, res) => {
console.log(`服务启动,运行在: http://127.0.0.1:${port} `);
});
})
.catch((err) => {
console.log("数据库连接失败");
});

(2) 创建 mongodb 模型文件 /models/blog.js

1
2
3
4
5
6
7
8
9
10
11
12
//引入 mongoose
const { set } = require("express/lib/application");
const mongoose = require("mongoose");

//定义 Schama
const schma = mongoose.schma({
title: String,
content: String,
});

//实例化模型并导出
module.exports = mongoose.model("blog", schma);

(3)创建 Express 路由文件:/routes.js

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
// 引入 express,model
const express = require("express");
const blog = require("./models/blog");

//创建 router 实例
const router = express.Router();

//创建查询全部数据 get 请求
router.get("/blog", async (req, res) => {
// 构建异步回调函数

const bloglist = await blog.find(); //查询全部数据,结果赋值给变量 bloglist
res.send(bloglist); //将bloglist 发送到api服务
});

// 将 router 实例导出到模块
module.exports = router;

(4) 将路由文件引入到主入口文件 /app.js

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
// 引入工具包
const express = require("express");
const mongoose = require("mongoose");

//引入路由文件
const routes = require("./routes");

// 连接MongoDB数据库,并在成功回调时,启动http服务
mongoose
.connect("mongodb://127.0.0.1:27017/mydb")
.then(() => {
//创建实例
const app = express();

//使用中间件
app.use(express.json());

//使用路由
app.use("/api", routes);

//设定监听端口
const port = 3000;
//启动服务
app.listen(port, "127.0.0.1", (req, res) => {
console.log(`服务启动,运行在: http://127.0.0.1:${port} `);
});
})
.catch((err) => {
console.log("数据库连接失败");
});

保存项目,访问:http://127.0.0.1:3000/api/blog 呈现空列表(此时数据库没有文件):

1
2
3
[

]

完善查看、创建、修改、删除接口

(1)创建数据,在 /routes.js get 请求块下补充内容:

1
2
3
4
5
6
7
8
9
10
11
12
//创建新增数据 post 请求
router.post("/blog", async (req, res) => {
// 构建异步回调函数

const postdata = new blog({
//调用模型创建数据实体
title: req.body.title,
content: req.body.content,
});
await postdata.save(); //保存实体对象到数据库
res.send(postdata); //将创建的模型 发送到api服务接口
});

(2)查找指定 ID 文档数据,在 /routes.js post 请求块下补充内容:

1
2
3
4
5
6
7
8
9
10
11
12
13
//查找指定ID数据 get 请求
router.get("/blog/:id", async (req, res) => {
// 构建异步回调函数

try {
const oneid = req.params.id; //提取请求当中的ID
const blogdata = await blog.findOne({ _id: oneid }); //根据ID查找文档,赋值给变量
res.send(blogdata); //将找到的数据发送到api服务接口
} catch {
res.status(404); //处理没有数据的情况
res.send({ error: "没有这条数据" });
}
});

(3)更新指定 ID 文档数据,在 /routes.js get 块下补充内容:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
//更新指定ID数据 post 请求
router.post("/blog/:id", async (req, res) => {
// 构建异步回调函数

try {
const oneid = req.params.id; //提取请求当中的ID

const blogdata = await blog.findOne({ _id: oneid }); //根据ID查找文档,赋值到变量

if (req.body.title) {
blogdata.title = req.body.title;
}

if (req.body.content) {
blogdata.content = req.body.content;
}

await blogdata.save();
res.send(blogdata); //将找到的数据发送到api服务接口
} catch {
res.status(404); //处理没有数据的情况
res.send({ error: "没有这条数据" });
}
});

(4)删除指定 ID 文档数据,在 /routes.js post 块下补充内容:

1
2
3
4
5
6
7
8
9
10
11
//删除指定ID数据 delete 请求
router.delete("/blog/:id", async (req,res)=>{ // 构建异步回调函数
try{
const oneid = req.params.id //提取请求当中的ID
await blog.deleteOne({_id:oneid}) //根据ID删除文档
res.status(204).send() //指定返回状态码
}catch{
res.status(404) //处理没有数据的情况
res.send({error:"没有这条数据"})
}
})

完整版 /routes.js 内容

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
// 引入 express,路由
const express = require("express");
const blog = require("./models/blog");

//创建 router 实例
const router = express.Router();

//1.1创建查询全部数据 get 请求
router.get("/blog", async (req, res) => {
// 构建异步回调函数

const bloglist = await blog.find(); //查询全部数据,结果赋值给变量 bloglist
res.send(bloglist); //将bloglist 发送到api服务
});

//1.2创建新增数据 post 请求
router.post("/blog", async (req, res) => {
// 构建异步回调函数
const postdata = new blog({
//调用模型创建数据实体
title: req.body.title,
content: req.body.content,
});
await postdata.save(); //保存数据到数据库
res.send(postdata); //将创建的模型 发送到api服务接口
});

//1.3查找指定ID数据 get 请求
router.get("/blog/:id", async (req, res) => {
// 构建异步回调函数
try {
const oneid = req.params.id; //提取请求当中的ID
const blogdata = await blog.findOne({ _id: oneid }); //根据ID查找文档,赋值结果到变量
res.send(blogdata); //将找到的数据发送到api服务接口
} catch {
res.status(404); //处理没有数据的情况
res.send({ error: "没有这条数据" });
}
});

//1.4更新指定ID数据 post 请求
router.post("/blog/:id", async (req, res) => {
// 构建异步回调函数
try {
const oneid = req.params.id; //提取请求当中的ID
const blogdata = await blog.findOne({ _id: oneid }); //根据ID查找文档,赋值结果到变量
if (req.body.title) {
blogdata.title = req.body.title;
}
if (req.body.content) {
blogdata.content = req.body.content;
}
await blogdata.save();
res.send(blogdata); //将找到的数据发送到api服务接口
} catch {
res.status(404); //处理没有数据的情况
res.send({ error: "没有这条数据" });
}
});

//1.5删除指定ID数据 delete 请求
router.delete("/blog/:id", async (req, res) => {
// 构建异步回调函数
try {
const oneid = req.params.id; //提取请求当中的ID
await blog.deleteOne({ _id: oneid }); //根据ID删除文档
res.status(204).send(); //指定返回状态码
} catch {
res.status(404); //处理没有数据的情况
res.send({ error: "没有这条数据" });
}
});

// 将 router 实例导出到模块
module.exports = router;