理解 Nodejs 中的 MVC 模式
这是使用 Nodejs、Express、Mongoose 和 Jest 进行测试驱动开发的第二部分。在第一部分中,我们搭建了开发环境并运行了第一个测试。在本教程中,我们将重点介绍如何使用 MVC 架构构建端点。
术语定义
MVC——模型视图控制器
模型视图控制器是一种软件架构模式,它将应用程序逻辑分为三个相互关联的元素:模型、视图和控制器。
Restful API
REST 是“表述性状态转移”的缩写,而 API 是“应用程序接口”的缩写。RESTful API 是一种使用 HTTP 请求访问和使用数据的应用程序接口 (API) 的架构风格。
我猜你对本教程涉及的术语应该很熟悉。我们开始吧。
在上一篇教程中,我们创建了一个非常基本的文件夹结构,其中包含一些依赖项。现在,让我们安装 API 开发所需的依赖项。
$ npm i --save-dev body-parser dotenv nodemon
安装后,您的 package.json 文件应如下所示。
{
"name": "tdd-with-nodejs",
"version": "1.0.0",
"description": "",
"main": "index.js",
"scripts": {
"test": "jest",
"start": "nodemon index.js"
},
"keywords": [],
"author": "",
"license": "ISC",
"devDependencies": {
"body-parser": "^1.19.0",
"dotenv": "^8.2.0",
"express": "^4.17.1",
"jest": "^26.6.3",
"mongoose": "^5.11.9",
"nodemon": "^2.0.6"
}
}
您注意到,我们已将初始化脚本配置为使用 nodemon 运行,nodemon 将跟踪对 index.js 文件所做的每个更改,并相应地刷新我们的应用程序。接下来,让我们设置一个服务器。在应用程序的根目录中创建一个名为 index.js 的新文件,并粘贴以下代码。
require('dotenv').config();
const mongoose = require("mongoose");
//const articles = require("./routes/article.routes");
const bodyParser = require("body-parser");
const app = exepress();
const port = 8000;
mongoose.connect(process.env.mongoURI, {useNewUrlParser: true, useCreateIndex: true, useUnifiedTopology: true })
.then(res => console.log(`Connection Succesful ${res}`))
.catch(err => console.log(`Error in DB connection ${err}`));
//body-parser config;
app.use(exepress.json());
app.use(bodyParser.urlencoded({extended: true }));
app.use(bodyParser.json());
app.get("/", (req, res) => {
res.send(`<h1>Hello!</h1>`)
});
app.listen(port, () => {
console.log(`Application is listening at port ${port}`);
});
//register the enpoints
//app.use("/api/v1/articles", articles);
不要忘记创建一个.env文件并添加数据库 URI,如下所示:mongoURI=mongodb+srv://your-db-uri。接下来,在终端上输入以下命令来启动应用程序。
$ npm run start
你的终端应该会收到如下响应:应用程序正在监听 8000 端口&连接成功 [object Object]。如果你打开http://localhost:8000 ,屏幕上应该也会显示“Hello!” 。
本教程旨在教您如何正确构建Nodjs应用程序以适应 MVC 模式,因此,我们将业务逻辑与控制器和路由文件分离。我们将在本系列的最后一篇教程“分层结构”教程中详细学习这一点。
构建模型(Article.js)
接下来,让我们创建模型。在项目根目录中创建一个新文件夹,导航到该文件夹,创建一个名为Article.js的新文件,然后复制粘贴以下代码以创建 API 的模型。
const mongoose = require("mongoose");
const Schema = mongoose.Schema;
const articleSchema = Schema({
title:{
type: String,
required: true,
},
body:{
type: String,
required: true,
},
article_image: {
type: String,
required: false,
},
date:{
type: Date,
default: Date.now(),
}
});
module.exports = Article = mongoose.model("Article", articleSchema);
我们的模型非常基础,它包含一个title、body和一个 date对象。您可以阅读此处的官方文档,了解更多关于使用 Mongoose 构建MongoDB Schemas 的信息。
构建文章服务(ArticleService.js)
要构建ArticleService.js,您需要创建一个名为 services 的文件夹来存放我们的ArticleService.js文件。将以下代码复制粘贴到您的ArticleService.js 文件中。
const Article = require("../models/Article");
module.exports = class ArticleService{
static async getAllArticles(){
try {
const allArticles = await Article.find();
return allArticles;
} catch (error) {
console.log(`Could not fetch articles ${error}`)
}
}
static async createArticle(data){
try {
const newArticle = {
title: data.title,
body: data.body,
article_image: data.article_image
}
const response = await new Article(newArticle).save();
return response;
} catch (error) {
console.log(error);
}
}
static async getArticlebyId(articleId){
try {
const singleArticleResponse = await Article.findById({_id: articleId});
return singleArticleResponse;
} catch (error) {
console.log(`Article not found. ${error}`)
}
}
static async updateArticle(title, body, articleImage){
try {
const updateResponse = await Article.updateOne(
{title, body, articleImage},
{$set: {date: new Date.now()}});
return updateResponse;
} catch (error) {
console.log(`Could not update Article ${error}` );
}
}
static async deleteArticle(articleId){
try {
const deletedResponse = await Article.findOneAndDelete(articleId);
return deletedResponse;
} catch (error) {
console.log(`Could ot delete article ${error}`);
}
}
}
构建控制器(article.controller.js)
接下来,让我们开始编写 API 端点,在根目录中创建一个名为controllers的新文件夹,导航到该文件夹,然后创建一个名为article.controller.js的新文件。复制粘贴以下代码。
const ArticleService = require("../services/ArticleService");
module.exports = class Article{
static async apiGetAllArticles(req, res, next){
try {
const articles = await ArticleService.getAllArticles();
if(!articles){
res.status(404).json("There are no article published yet!")
}
res.json(articles);
} catch (error) {
res.status(500).json({error: error})
}
}
static async apiGetArticleById(req, res, next){
try {
let id = req.params.id || {};
const article = await ArticleService.getArticlebyId(id);
res.json(article);
} catch (error) {
res.status(500).json({error: error})
}
}
static async apiCreateArticle(req, res, next){
try {
const createdArticle = await ArticleService.createArticle(req.body);
res.json(createdArticle);
} catch (error) {
res.status(500).json({error: error});
}
}
static async apiUpdateArticle(req, res, next){
try {
const comment = {}
comment.title = req.body.title;
comment.body = req.body.body;
comment.articleImage = req.body.article_image
const updatedArticle = await ArticleService.updateArticle(comment);
if(updatedArticle.modifiedCount === 0){
throw new Error("Unable to update article, error occord");
}
res.json(updatedArticle);
} catch (error) {
res.status(500).json({error: error});
}
}
static async apiDeleteArticle(req, res, next){
try {
const articleId = req.params.id;
const deleteResponse = await ArticleService.deleteArticle(articleId)
res.json(deleteResponse);
} catch (error) {
res.status(500).json({error: error})
}
}
}
构建路线(article.routes.js)
为了与我们的端点通信,我们需要设置相应的路由和请求。创建一个名为routes的新文件夹,并在其中创建一个名为article.routes.js的新文件。您可以随意命名文件夹,但最好保持目录和文件名有意义。
const express = require("express");
const router = express.Router();
const ArticleCtrl = require("../controllers/article.controller");
router.get("/", ArticleCtrl.apiGetAllArticles);
router.post("/", ArticleCtrl.apiCreateArticle);
router.get("/article/:id", ArticleCtrl.apiGetArticleById);
router.put("/article/:id", ArticleCtrl.apiUpdateArticle);
router.delete("/article/:id", ArticleCtrl.apiDeleteArticle);
module.exports = router;
如果您已经按照本教程进行了到目前为止的操作,那么您的文件夹结构实际上应该像下面的代码片段一样。
├── tdd-with-nodejs
├── controllers
├── article.controller.js
├── models
├── Article.js
├── routes
├── article.routes.js
├── services
├── articleService.js
├── test
整合起来
使用 MVC 模式时,务必遵循关注点分离 (SoC) 技术。关注点分离 (SoC) 是一种设计原则,用于将软件应用程序划分为不同的部分,以便每个部分分别处理一个关注点。关注点是一组影响软件应用程序代码的信息。我们将在下一篇教程(也是本系列的最后一篇)中深入探讨这个主题。
在结束之前,让我们先测试一下其中一个端点。使用您选择的 API 测试工具向/api/v1/articles端点发送一个POST请求。在我的例子中,我们使用了Postman。您应该会收到一个响应对象,作为您新创建的文章的响应,类似于下面的代码片段。
本教程到此结束。恭喜你完成了本系列的学习。下篇教程再见。
文章来源:https://dev.to/eetukudo_/understanding-mvc-pattern-in-nodejs-2bdn