理解Nodejs中的MVC模式

522 阅读3分钟

作者:Emmanuel Etukudo;本文翻译自:dev.to/eaetukudo/u…

这是Nodejs、Express、Mongoose和Jest的测试驱动开发的第二部分,在第一部分中,我们建立了开发环境并运行了第一个测试。在本教程中,我们将侧重于使用MVC架构构建端点。

术语定义

MVC-模型视图控制器

模型视图控制器是一种软件体系结构模式,它涉及将应用程序逻辑分离成三个相互连接的元素模型、视图和控制器。

恢复API

REST是表示状态传输的首字母缩略词,API是应用程序接口的首字母缩略词。RESTful API是应用程序接口(API)的架构样式,它使用HTTP请求访问和使用数据。

我猜你对本教程中涉及的术语很熟悉。让我们开始吧。

在前面的教程中,我们有一个非常基本的文件夹结构,几乎没有依赖关系。让我们为我们的应用编程接口开发安装所需的依赖关系。

$ 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"
  }
}

您注意到我们已经配置了我们的初始化脚本来运行no恶魔,no恶魔将跟踪对我们的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: mongo URI=mongo db+srv://your-db-uri.接下来,通过在终端上键入下面的命令来启动应用程序。

$ npm run start

您应该在您的终端上得到一个响应,上面写着:应用程序正在8000端口监听&连接成功[对象对象]。如果您打开超文本传输协议://localhost: 8000,您应该也会得到“你好!”登录到您的屏幕上。

本教程旨在教您如何正确地构建Nodjs应用程序以适应MVC模式,因此,我们将把业务逻辑与控制器和路由文件分开。我们将在本系列的最后教程分层结构教程中了解更多信息。

建立模型(Article.js)

接下来,让我们创建我们的模型。

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);

我们的模型非常基础,它有一个标题、正文和日期对象。通过阅读这里官方文档,您可以了解更多关于使用Mongoose构建MongoDB模式的信息。

构建文章服务(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)

接下来,让我们开始编写我们的应用编程接口端点,在根目录中创建一个名为控制器的新文件夹**,导航到该文件夹,并创建一个名为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)

要与我们的端点通信,我们需要设置相应请求的路由。创建一个名为路由的新文件夹,在该文件夹中,创建一个名为**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/v1/articles端点发送一个POST请求。在我的例子中,邮递员您应该获得响应对象作为您新创建文章的响应,类似于下面的片段。

以上就是本教程的全部内容,下期教程再见。