MERN 堆栈 TODO 应用程序 [后端]
我们将使用MERN堆栈(MongoDB用于数据库、Express后端Node和React前端)创建一个最小的全栈应用程序来执行CRUD操作。
我们的应用程序将允许用户
- 创建待办事项
- 阅读待办事项
- 更新待办事项
- 删除待办事项
本系列应该能让您理解CRUD使用堆栈的操作MERN。
在本部分(第 1 部分)中,我们将
npm使用并安装必要的包初始化我们的后端- 设置 MongoDB 数据库
Node使用和设置服务器Express- 创建数据库模式来定义
Todo - 设置从数据库到
create、read和文档update的API 路由delete API使用Insomnia测试我们的路线
在我们开始之前
先决条件
应该至少对基本的编程概念有一些基本的了解,并且有一定的HTML经验CSS。JavaScript
这篇文章的目的并不是解释MERN堆栈,而是对如何使用它构建全栈应用程序进行了很好的介绍。
安装
VS Code或任何其他编辑器- 最新版本
Node.js Insomnia或邮递员PrettierVS 代码扩展来格式化代码
第 1 部分:创建后端
1.初始化我们的项目
创建一个新文件夹并将其命名为您喜欢的任何名称,然后在 VS 代码中打开该文件夹并从命令提示符运行以下代码。
npm init -y
运行此命令后,您将发现一个package.json文件夹。
2. 设置 package.json
i. 安装以下依赖项
在终端中运行以下命令来安装依赖项
npm i cors dotenv express mongoose
cors:允许跨域 API 调用:需要从文件dotenv访问数据:node.js 的 Web 应用程序框架:需要定义数据库模式并连接到.envexpressmongoosemongoDB
ii. 安装以下开发依赖项
现在安装以下开发依赖项,-D用于安装开发依赖项。
npm i -D nodemon
安装依赖项后,package.json文件夹应如下所示。
// package.json
{
"name": "mern-todo",
"version": "1.0.0",
"description": "",
"main": "index.js",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1"
},
"keywords": [],
"author": "",
"license": "ISC",
"dependencies": {
"config": "^3.3.6",
"cors": "^2.8.5",
"dotenv": "^10.0.0",
"express": "^4.17.1",
"mongoose": "^5.13.2"
},
"devDependencies": {
"nodemon": "^2.0.11"
}
}
iii. 将main入口点更改为server.js
现在,创建一个server.js文件和一个.env。该server.js文件将作为服务器的入口点,并且.env将包含MONGO_URI。我们还必须在 中进行以下更改package.json
//package.json
{
"name": "mern-todo",
"version": "1.0.0",
"description": "",
"main": "server.js", //changed
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1"
},
"keywords": [],
"author": "",
"license": "ISC",
"dependencies": {
"config": "^3.3.6",
"cors": "^2.8.5",
"dotenv": "^10.0.0",
"express": "^4.17.1",
"mongoose": "^5.13.2"
},
"devDependencies": {
"nodemon": "^2.0.11"
}
}
现在,创建以下文件夹
-
config:在config文件夹中,创建一个名为的文件db.js。此文件将包含连接数据库所需的代码MongoDB。 -
controllers:该controllers文件夹将包含端点与数据库通信的方法的文件。 -
models:该models文件夹将包含定义MongoDB schema -
routers:该routers文件夹将包含扩展名为 的文件endpoints。
在此阶段,文件结构应如下所示
.
├── config
│ └── db.js
├── controllers
│ └── todo.js
├── models
│ └── todo.js
├── node_modules
├── routes
│ └── todo.js
├── .env
├── server.js
├── package-lock.json
└── package.json
iv. 将scripts以下内容更改为
"scripts": {
"start":"node server.js",
"dev":"nodemon server.js"
}
该package.json文件应如下所示
{
"name": "mern-todo",
"version": "1.0.0",
"description": "",
"main": "server.js",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1",
"start": "node server.js", //added
"dev": "nodemon server.js" //added
},
"keywords": [],
"author": "",
"license": "ISC",
"dependencies": {
"config": "^3.3.6",
"cors": "^2.8.5",
"dotenv": "^10.0.0",
"express": "^4.17.1",
"mongoose": "^5.13.2"
},
"devDependencies": {
"nodemon": "^2.0.11"
}
}
v. 设置服务器
我们将执行以下操作来设置服务器
- 进口
express - 使用初始化我们的应用程序
express() - 使用以下
get方法为端点设置方法http://localhost:8000app.get() PORT将我们的服务器设置8000为运行PORT使用我们的应用程序来收听app.listen()
.
├── config
│ └── db.js
├── controllers
│ └── todo.js
├── models
│ └── todo.js
├── node_modules
├── routes
│ └── todo.js
├── .env
├── server.js <-- we are here
├── package-lock.json
└── package.json
代码如下
| // server.js | |
| const express = require("express"); | |
| const app = express(); | |
| // initialize middleware | |
| app.use(express.json({ extended: false })); | |
| app.get("/", (req, res) => res.send("Server up and running")); | |
| // setting up port | |
| const PORT = process.env.PORT || 8000; | |
| app.listen(PORT, () => { | |
| console.log(`server is running on http://localhost:${PORT}`); | |
| }); |
| // server.js | |
| const express = require("express"); | |
| const app = express(); | |
| // initialize middleware | |
| app.use(express.json({ extended: false })); | |
| app.get("/", (req, res) => res.send("Server up and running")); | |
| // setting up port | |
| const PORT = process.env.PORT || 8000; | |
| app.listen(PORT, () => { | |
| console.log(`server is running on http://localhost:${PORT}`); | |
| }); |
并使用以下代码启动服务器nodemon。请确保从项目目录运行以下命令。
npm run dev
如果服务器已成功启动,则它应该在终端中显示以下消息
[nodemon] 2.0.11
[nodemon] to restart at any time, enter `rs`
[nodemon] watching path(s): *.*
[nodemon] watching extensions: js,mjs,json
[nodemon] starting `node server.js`
server is running on http://localhost:8000
您也可以http://localhost:8000在浏览器上打开。
MONGO URIvi.从mongoDB获取
要连接到数据库,我们需要mongoDB集合的链接。
- 登录mongoDB
- 创建新项目
- 构建集群
- 选择云提供商
- 创建集群
- 等待集群创建。
- 点击连接
- 点击
allow access from anywhere。然后Add IP address
- 创建数据库用户。您需要
username和password。MongoDB URI - 点击
Choose a connection method - 点击
Connect your application -
选择以下驱动程序和版本
-
复制
mongodb+srv并粘贴到.env文件中
vii. 设置.env文件
//.env
MONGO_URI = mongodb+srv://<username>:<password>@cluster0.owmij.mongodb.net
将<username>和替换<password>为您在步骤 9 中设置的数据库用户名和密码。
viii. 连接数据库
.
├── config
│ └── db.js <-- we are here
├── controllers
│ └── todo.js
├── models
│ └── todo.js
├── node_modules
├── routes
│ └── todo.js
├── .env
├── server.js
├── package-lock.json
└── package.json
现在,打开文件夹db.js中的文件config并添加以下更改。
- 进口
mongoose - 导入
MONGO_URI自.env - 定义
connectDB连接数据库的方法 - 导出
connectDB要调用的方法server.js
| // config/db.js | |
| const mongoose = require("mongoose"); | |
| const db = process.env.MONGO_URI; | |
| const connectDB = async () => { | |
| try { | |
| await mongoose.connect(db, { | |
| useNewUrlParser: true, | |
| useUnifiedTopology: true, | |
| }); | |
| console.log("MongoDB is connected"); | |
| } catch (err) { | |
| console.error(err.message); | |
| process.exit(1); | |
| } | |
| }; | |
| module.exports = connectDB; |
| // config/db.js | |
| const mongoose = require("mongoose"); | |
| const db = process.env.MONGO_URI; | |
| const connectDB = async () => { | |
| try { | |
| await mongoose.connect(db, { | |
| useNewUrlParser: true, | |
| useUnifiedTopology: true, | |
| }); | |
| console.log("MongoDB is connected"); | |
| } catch (err) { | |
| console.error(err.message); | |
| process.exit(1); | |
| } | |
| }; | |
| module.exports = connectDB; |
在文件中添加以下更改server.js。
- 进口
dotenv - 导入
connectDB方法来自config/db.js - 调用该
connectDB方法。
让我们在server.js
| // server.js | |
| require("dotenv").config(); //added | |
| const express = require("express"); | |
| const connectDB = require("./config/db"); //added | |
| const app = express(); | |
| // connect database | |
| connectDB();//added | |
| // initialize middleware | |
| app.use(express.json({ extended: false })); | |
| app.get("/", (req, res) => res.send("Server up and running")); | |
| // setting up port | |
| const PORT = process.env.PORT || 8000; | |
| app.listen(PORT, () => { | |
| console.log(`server is running on http://localhost:${PORT}`); | |
| }); |
| // server.js | |
| require("dotenv").config(); //added | |
| const express = require("express"); | |
| const connectDB = require("./config/db"); //added | |
| const app = express(); | |
| // connect database | |
| connectDB();//added | |
| // initialize middleware | |
| app.use(express.json({ extended: false })); | |
| app.get("/", (req, res) => res.send("Server up and running")); | |
| // setting up port | |
| const PORT = process.env.PORT || 8000; | |
| app.listen(PORT, () => { | |
| console.log(`server is running on http://localhost:${PORT}`); | |
| }); |
保存更改后,它将重新启动服务器或使用命令npm run dev。终端应该显示我们在try块下MongoDB is connected添加的消息。db.js
ix. 定义数据库模式
在 models 文件夹中创建一个todo.js文件。我们将在此文件中定义数据库模式。
.
├── config
│ └── db.js
├── controllers
│ └── todo.js
├── models
│ └── todo.js <-- we are here
├── node_modules
├── routes
│ └── todo.js
├── .env
├── server.js
├── package-lock.json
└── package.json
- 进口
mongoose - 创建一个
Schema叫TodoSchema - 我们将为待办事项添加两个字段
title;description - 类型
title为String并且为必填字段 - 类型
description为,String并且不是必填字段 - 导出模型
代码如下
| // models/todo.js | |
| const mongoose = require("mongoose"); | |
| const TodoSchema = new mongoose.Schema({ | |
| title: { | |
| type: "String", | |
| required: true, | |
| }, | |
| description: { | |
| type: "String", | |
| }, | |
| }); | |
| const Todo = mongoose.model("todo", TodoSchema); | |
| module.exports = Todo; |
| // models/todo.js | |
| const mongoose = require("mongoose"); | |
| const TodoSchema = new mongoose.Schema({ | |
| title: { | |
| type: "String", | |
| required: true, | |
| }, | |
| description: { | |
| type: "String", | |
| }, | |
| }); | |
| const Todo = mongoose.model("todo", TodoSchema); | |
| module.exports = Todo; |
x. 定义终点
.
├── config
│ └── db.js
├── controllers
│ └── todo.js
├── models
│ └── todo.js
├── node_modules
├── routes
│ └── todo.js <-- we are here
├── .env
├── server.js
├── package-lock.json
└── package.json
CRUD我们将定义操作的终点
- 进口
express - 初始化
router - 我们稍后将从
controllers - 为所有待办事项定义一个
GET方法read - 定义一个
POST方法用于create新的待办事项 PUT为update现有待办事项定义方法DELETE为delete现有待办事项定义方法- 导出
router
代码如下
| // router/todo.js | |
| const express = require("express"); | |
| const router = express.Router(); | |
| /** | |
| * @route GET api/todo | |
| * @description get all todo | |
| * @access public | |
| */ | |
| router.get("/"); | |
| /** | |
| * @route POST api/todo | |
| * @description add a new todo | |
| * @access public | |
| */ | |
| router.post("/"); | |
| /** | |
| * @route PUT api/todo/:id | |
| * @description update todo | |
| * @access public | |
| */ | |
| router.put("/:id"); | |
| /** | |
| * @route DELETE api/todo/:id | |
| * @description delete todo | |
| * @access public | |
| */ | |
| router.delete("/:id"); | |
| module.exports = router; |
| // router/todo.js | |
| const express = require("express"); | |
| const router = express.Router(); | |
| /** | |
| * @route GET api/todo | |
| * @description get all todo | |
| * @access public | |
| */ | |
| router.get("/"); | |
| /** | |
| * @route POST api/todo | |
| * @description add a new todo | |
| * @access public | |
| */ | |
| router.post("/"); | |
| /** | |
| * @route PUT api/todo/:id | |
| * @description update todo | |
| * @access public | |
| */ | |
| router.put("/:id"); | |
| /** | |
| * @route DELETE api/todo/:id | |
| * @description delete todo | |
| * @access public | |
| */ | |
| router.delete("/:id"); | |
| module.exports = router; |
xi. 定义终点方法
controllers我们将在文件夹中定义端点的方法
.
├── config
│ └── db.js
├── controllers
│ └── todo.js <-- we are here
├── models
│ └── todo.js
├── node_modules
├── routes
│ └── todo.js
├── .env
├── server.js
├── package-lock.json
└── package.json
- 导入
Todo模型models/todo - 定义以下四个方法
getAllTodopostCreateTodoputUpdateTododeleteTodo
- 导出所有方法
| // controllers/todo.js | |
| const Todo = require("../models/todo"); | |
| exports.getAllTodo = (req, res) => { | |
| Todo.find() | |
| .then((todo) => res.json(todo)) | |
| .catch((err) => | |
| res | |
| .status(404) | |
| .json({ message: "Todo not found", error: err.message }) | |
| ); | |
| }; | |
| exports.postCreateTodo = (req, res) => { | |
| Todo.create(req.body) | |
| .then((data) => res.json({ message: "Todo added successfully", data })) | |
| .catch((err) => | |
| res | |
| .status(400) | |
| .json({ message: "Failed to add todo", error: err.message }) | |
| ); | |
| }; | |
| exports.putUpdateTodo = (req, res) => { | |
| Todo.findByIdAndUpdate(req.params.id, req.body) | |
| .then((data) => res.json({ message: "updated successfully", data })) | |
| .catch((err) => | |
| res | |
| .status(400) | |
| .json({ message: "Failed to update todo", error: err.message }) | |
| ); | |
| }; | |
| exports.deleteTodo = (req, res) => { | |
| Todo.findByIdAndRemove(req.params.id, req.body) | |
| .then((data) => | |
| res.json({ message: "todo deleted successfully", data }) | |
| ) | |
| .catch((err) => | |
| res | |
| .status(404) | |
| .json({ message: "book not found", error: err.message }) | |
| ); | |
| }; |
| // controllers/todo.js | |
| const Todo = require("../models/todo"); | |
| exports.getAllTodo = (req, res) => { | |
| Todo.find() | |
| .then((todo) => res.json(todo)) | |
| .catch((err) => | |
| res | |
| .status(404) | |
| .json({ message: "Todo not found", error: err.message }) | |
| ); | |
| }; | |
| exports.postCreateTodo = (req, res) => { | |
| Todo.create(req.body) | |
| .then((data) => res.json({ message: "Todo added successfully", data })) | |
| .catch((err) => | |
| res | |
| .status(400) | |
| .json({ message: "Failed to add todo", error: err.message }) | |
| ); | |
| }; | |
| exports.putUpdateTodo = (req, res) => { | |
| Todo.findByIdAndUpdate(req.params.id, req.body) | |
| .then((data) => res.json({ message: "updated successfully", data })) | |
| .catch((err) => | |
| res | |
| .status(400) | |
| .json({ message: "Failed to update todo", error: err.message }) | |
| ); | |
| }; | |
| exports.deleteTodo = (req, res) => { | |
| Todo.findByIdAndRemove(req.params.id, req.body) | |
| .then((data) => | |
| res.json({ message: "todo deleted successfully", data }) | |
| ) | |
| .catch((err) => | |
| res | |
| .status(404) | |
| .json({ message: "book not found", error: err.message }) | |
| ); | |
| }; |
getAllTodo:该find()方法将返回集合中的所有待办事项。如果集合为空,则返回404错误。
postCreateTodo:该create()方法将创建一个待办事项并返回成功消息。否则,它将返回400错误。
putUpdateTodo:findByIdAndUpdate()需要两个参数id和data来更新待办事项。id参数 将从 中提取req.params.id。
deleteTodo:该findByIdAndRemove()方法只需要一个参数,即id待办事项。
xii. 将方法添加到端点
.
├── config
│ └── db.js
├── controllers
│ └── todo.js
├── models
│ └── todo.js
├── node_modules
├── routes
│ └── todo.js <-- we are here
├── .env
├── server.js
├── package-lock.json
└── package.json
CRUD导入操作方法- 将方法添加到端点
| // routes/todo.js | |
| const express = require("express"); | |
| const router = express.Router(); | |
| const { | |
| getAllTodo, | |
| postCreateTodo, | |
| putUpdateTodo, | |
| deleteTodo, | |
| } = require("../controllers/todo"); | |
| /** | |
| * @route GET api/todo | |
| * @description get all todo | |
| * @access public | |
| */ | |
| router.get("/", getAllTodo); | |
| /** | |
| * @route POST api/todo | |
| * @description add a new todo | |
| * @access public | |
| */ | |
| router.post("/", postCreateTodo); | |
| /** | |
| * @route PUT api/todo/:id | |
| * @description update todo | |
| * @access public | |
| */ | |
| router.put("/:id", putUpdateTodo); | |
| /** | |
| * @route DELETE api/todo/:id | |
| * @description delete todo | |
| * @access public | |
| */ | |
| router.delete("/:id", deleteTodo); | |
| module.exports = router; |
| // routes/todo.js | |
| const express = require("express"); | |
| const router = express.Router(); | |
| const { | |
| getAllTodo, | |
| postCreateTodo, | |
| putUpdateTodo, | |
| deleteTodo, | |
| } = require("../controllers/todo"); | |
| /** | |
| * @route GET api/todo | |
| * @description get all todo | |
| * @access public | |
| */ | |
| router.get("/", getAllTodo); | |
| /** | |
| * @route POST api/todo | |
| * @description add a new todo | |
| * @access public | |
| */ | |
| router.post("/", postCreateTodo); | |
| /** | |
| * @route PUT api/todo/:id | |
| * @description update todo | |
| * @access public | |
| */ | |
| router.put("/:id", putUpdateTodo); | |
| /** | |
| * @route DELETE api/todo/:id | |
| * @description delete todo | |
| * @access public | |
| */ | |
| router.delete("/:id", deleteTodo); | |
| module.exports = router; |
xiii. 在server.js
.
├── config
│ └── db.js
├── controllers
│ └── todo.js
├── models
│ └── todo.js
├── node_modules
├── routes
│ └── todo.js
├── .env
├── server.js <-- we are here
├── package-lock.json
└── package.json
完成后端的最后一部分是将端点添加到server.js文件中。
- 进口
routes/todo.js - 将路由端点添加到中间件
| // server.js | |
| require("dotenv").config(); | |
| const express = require("express"); | |
| const connectDB = require("./config/db"); | |
| const app = express(); | |
| // routes | |
| const todo = require("./routes/todo"); // added | |
| // connect database | |
| connectDB(); | |
| // initialize middleware | |
| app.use(express.json({ extended: false })); | |
| app.get("/", (req, res) => res.send("Server up and running")); | |
| // use routes | |
| app.use("/api/todo", todo); // added | |
| // setting up port | |
| const PORT = process.env.PORT || 8000; | |
| app.listen(PORT, () => { | |
| console.log(`server is running on http://localhost:${PORT}`); | |
| }); |
| // server.js | |
| require("dotenv").config(); | |
| const express = require("express"); | |
| const connectDB = require("./config/db"); | |
| const app = express(); | |
| // routes | |
| const todo = require("./routes/todo"); // added | |
| // connect database | |
| connectDB(); | |
| // initialize middleware | |
| app.use(express.json({ extended: false })); | |
| app.get("/", (req, res) => res.send("Server up and running")); | |
| // use routes | |
| app.use("/api/todo", todo); // added | |
| // setting up port | |
| const PORT = process.env.PORT || 8000; | |
| app.listen(PORT, () => { | |
| console.log(`server is running on http://localhost:${PORT}`); | |
| }); |
3 使用以下方法测试终点Insomnia
- 创建待办事项
我们将发送POST请求至http://localhost:8000/api/todo
- 阅读待办事项
我们将发送GET请求至http://localhost:8000/api/todo
您可以在mongoDB中检查更改collections
- 更新待办事项
要更新待办事项,我们将发送PUT请求至http://localhost:8000/api/todo/id
必须id从服务器的响应消息中获取。
{
"message": "Todo added successfully",
"data": {
"_id": "60ec0f9655f9735a60a2d967",
"title": "test todo",
"description": "test todo",
"__v": 0
}
}
要更新待办事项,我们需要id。我们将从预览选项卡的 获取 。id使用request和request 后,我们可以从获取。_ididpreviewGETPOST
- 删除待办事项
要删除待办事项,我们将发送DELETE请求至http://localhost:8000/api/todo/id
4. 添加cors
.
├── config
│ └── db.js
├── controllers
│ └── todo.js
├── models
│ └── todo.js
├── node_modules
├── routes
│ └── todo.js
├── .env
├── server.js <-- we are here
├── package-lock.json
└── package.json
添加cors后,我们就可以从前端应用程序(如 react)进行 api 调用。
| require("dotenv").config(); | |
| const express = require("express"); | |
| const cors = require("cors"); // added | |
| const connectDB = require("./config/db"); | |
| const app = express(); | |
| // routes | |
| const todo = require("./routes/todo"); | |
| // connect database | |
| connectDB(); | |
| // cors | |
| app.use(cors({ origin: true, credentials: true })); // added | |
| // initialize middleware | |
| app.use(express.json({ extended: false })); | |
| app.get("/", (req, res) => res.send("Server up and running")); | |
| // use routes | |
| app.use("/api/todo", todo); | |
| // setting up port | |
| const PORT = process.env.PORT || 8000; | |
| app.listen(PORT, () => { | |
| console.log(`server is running on http://localhost:${PORT}`); | |
| }); |
| require("dotenv").config(); | |
| const express = require("express"); | |
| const cors = require("cors"); // added | |
| const connectDB = require("./config/db"); | |
| const app = express(); | |
| // routes | |
| const todo = require("./routes/todo"); | |
| // connect database | |
| connectDB(); | |
| // cors | |
| app.use(cors({ origin: true, credentials: true })); // added | |
| // initialize middleware | |
| app.use(express.json({ extended: false })); | |
| app.get("/", (req, res) => res.send("Server up and running")); | |
| // use routes | |
| app.use("/api/todo", todo); | |
| // setting up port | |
| const PORT = process.env.PORT || 8000; | |
| app.listen(PORT, () => { | |
| console.log(`server is running on http://localhost:${PORT}`); | |
| }); |
您可以在GitHub上查看本博客的完整代码
文章来源:https://dev.to/mritunjaysaha/mern-stack-todo-application-backend-282a
后端开发教程 - Java、Spring Boot 实战 - msg200.com





