作者: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请求。在我的例子中,邮递员您应该获得响应对象作为您新创建文章的响应,类似于下面的片段。
以上就是本教程的全部内容,下期教程再见。