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
或邮递员Prettier
VS 代码扩展来格式化代码
第 1 部分:创建后端
1.初始化我们的项目
创建一个新文件夹并将其命名为您喜欢的任何名称,然后在 VS 代码中打开该文件夹并从命令提示符运行以下代码。
npm init -y
运行此命令后,您将发现一个package.json
文件夹。
2. 设置 package.json
i. 安装以下依赖项
在终端中运行以下命令来安装依赖项
npm i cors dotenv express mongoose
cors
:允许跨域 API 调用:需要从文件dotenv
访问数据:node.js 的 Web 应用程序框架:需要定义数据库模式并连接到.env
express
mongoose
mongoDB
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:8000
app.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 URI
vi.从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
- 定义以下四个方法
getAllTodo
postCreateTodo
putUpdateTodo
deleteTodo
- 导出所有方法
// 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 后,我们可以从获取。_id
id
preview
GET
POST
- 删除待办事项
要删除待办事项,我们将发送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