使用 Node.js、Express 和 MongoDB 构建 Restful CRUD API

x33g5p2x  于2021-10-21 转载在 Go  
字(9.1k)|赞(0)|评价(0)|浏览(506)

在本教程中,我们将使用 Node.js、Express 和 MongoDB 构建一个 RESTful CRUD(创建、检索、更新、删除)API。我们将使用 Mongoose 与 MongoDB 实例进行交互。

Express 是最流行的 node.js 网络框架之一。它建立在 node.js http 模块之上,并增加了对路由、中间件、视图系统等的支持。它非常简单和最小,不像其他框架那样做太多,从而降低了开发人员使用他们的灵活性自己的设计选择。

Mongoose 是 Node.js 和 MongoDB 的 ODM(对象文档映射)工具。它可以帮助您将代码中的对象转换为数据库中的文档,反之亦然。

在继续下一节之前,如果您还没有安装 MongoDB,请在您的机器上安装。查看 official MogngoDB installation manual 以获取有关安装的任何帮助。

###我们的应用程序

在本教程中,我们将构建一个简单的笔记应用程序。我们将构建用于创建、列出、编辑和删除笔记的 Rest API。

我们将从构建一个简单的 Web 服务器开始,然后继续配置数据库,构建 Note 模型和处理所有 CRUD 操作的不同路由。

最后,我们将使用 Postman 测试我们的 REST API。

此外,在这篇文章中,我们将大量使用 ES6 特性,如 letconstarrow functionspromises 等。熟悉这些是很好的特征。我推荐 this re-introduction to Javascript 来复习这些概念。

好!现在我们知道我们要构建什么,我们需要为我们的应用程序取一个很酷的名字。让我们调用我们的应用程序 EasyNotes

创建应用程序

1.启动您的终端并为应用程序创建一个新文件夹。

$ mkdir node-easy-notes-app

2.使用 package.json 文件初始化应用程序

转到应用程序的根文件夹并键入 npm init 以使用 package.json 文件初始化您的应用程序。

$ cd node-easy-notes-app
$ npm init
name: (node-easy-notes-app) 
version: (1.0.0) 
description: Never miss a thing in Life. Take notes quickly. Organize and keep track of all your notes.
entry point: (index.js) server.js
test command: 
git repository: 
keywords: Express RestAPI MongoDB Mongoose Notes
author: callicoder
license: (ISC) MIT
About to write to /Users/rajeevkumarsingh/node-easy-notes-app/package.json:

{
  "name": "node-easy-notes-app",
  "version": "1.0.0",
  "description": "Never miss a thing in Life. Take notes quickly. Organize and keep track of all your notes.",
  "main": "server.js",
  "scripts": {
    "test": "echo \"Error: no test specified\" && exit 1"
  },
  "keywords": [
    "Express",
    "RestAPI",
    "MongoDB",
    "Mongoose",
    "Notes"
  ],
  "author": "callicoder",
  "license": "MIT"
}

Is this ok? (yes) yes

请注意,我指定了一个名为 server.js 的文件作为我们应用程序的入口点。我们将在下一节中创建 server.js 文件。

3.安装依赖

我们将在我们的应用程序中需要 express、mongoose 和 body-parser 模块。让我们通过键入以下命令来安装它们 -

$ npm install express body-parser mongoose --save

我使用 --save 选项将所有依赖项保存在 package.json 文件中。最终的 package.json 文件如下所示 -

{
  "name": "node-easy-notes-app",
  "version": "1.0.0",
  "description": "Never miss a thing in Life. Take notes quickly. Organize and keep track of all your notes.",
  "main": "server.js",
  "scripts": {
    "test": "echo \"Error: no test specified\" && exit 1"
  },
  "keywords": [
    "Express",
    "RestAPI",
    "MongoDB",
    "Mongoose",
    "Notes"
  ],
  "author": "callicoder",
  "license": "MIT",
  "dependencies": {
    "body-parser": "^1.18.3",
    "express": "^4.16.3",
    "mongoose": "^5.2.8"
  }
}

我们的应用程序文件夹现在有一个 package.json 文件和一个 node_modules 文件夹 -

node-easy-notes-app
    └── node_modules/
    └── package.json

设置网络服务器

现在让我们创建应用程序的主要入口点。在应用程序的根文件夹中创建一个名为 server.js 的新文件,内容如下 -

const express = require('express');
const bodyParser = require('body-parser');

// create express app
const app = express();

// parse requests of content-type - application/x-www-form-urlencoded
app.use(bodyParser.urlencoded({ extended: true }))

// parse requests of content-type - application/json
app.use(bodyParser.json())

// define a simple route
app.get('/', (req, res) => {
    res.json({"message": "Welcome to EasyNotes application. Take notes quickly. Organize and keep track of all your notes."});
});

// listen for requests
app.listen(3000, () => {
    console.log("Server is listening on port 3000");
});

首先,我们导入 express 和 body-parser 模块。如您所知,Express 是我们将用于构建 REST API 的 Web 框架,body-parser 是一个模块,用于解析(各种内容类型的)请求并创建一个req.body 我们可以在路由中访问的对象。

然后,我们创建一个 express 应用,并使用 express 的 app.use() 方法添加两个 body-parser 中间件。 middleware 是一个可以访问 requestresponse 对象的函数。它可以执行任何代码、转换请求对象或返回响应。

**然后,**我们定义了一个简单的 GET 路由,它向客户端返回一条欢迎消息。

最后, 我们在端口 3000 上侦听传入连接。

好的!现在让我们运行服务器并转到 http://localhost:3000 访问我们刚刚定义的路由。

$ node server.js 
Server is listening on port 3000

配置和连接到数据库

我喜欢将应用程序的所有配置保存在一个单独的文件夹中。让我们在应用程序的根文件夹中创建一个新文件夹 config 来保存所有配置 -

$ mkdir config
$ cd config

现在,在 config 文件夹中创建一个新文件 database.config.js,内容如下:

module.exports = {
    url: 'mongodb://localhost:27017/easy-notes'
}

我们现在将在 server.js 中导入上述数据库配置并使用 mongoose 连接到数据库。

app.use(bodyParser.json()) 行之后的 server.js 文件中添加以下代码 -

// Configuring the database
const dbConfig = require('./config/database.config.js');
const mongoose = require('mongoose');

mongoose.Promise = global.Promise;

// Connecting to the database
mongoose.connect(dbConfig.url, {
    useNewUrlParser: true
}).then(() => {
    console.log("Successfully connected to the database");    
}).catch(err => {
    console.log('Could not connect to the database. Exiting now...', err);
    process.exit();
});

请运行服务器并确保您能够连接到数据库 -

$ node server.js 
Server is listening on port 3000
Successfully connected to the database

在 Mongoose 中定义 Note 模型

接下来,我们将定义 Note 模型。在应用程序的根文件夹中创建一个名为 app 的新文件夹,然后在 app 文件夹中创建另一个名为 models 的文件夹 -

$ mkdir -p app/models
$ cd app/models

现在,在 app/models 文件夹中创建一个名为 note.model.js 的文件,其中包含以下内容 -

const mongoose = require('mongoose');

const NoteSchema = mongoose.Schema({
    title: String,
    content: String
}, {
    timestamps: true
});

module.exports = mongoose.model('Note', NoteSchema);

Note 模型非常简单。它包含一个 title 和一个 content 字段。我还在架构中添加了一个时间戳选项。

Mongoose 使用此选项自动向架构添加两个新字段 - createdAtupdatedAt

使用 Express 定义路由

接下来是 Notes API 的路由。在 app 文件夹中创建一个名为 routes 的新文件夹。

$ mkdir app/routes
$ cd app/routes

现在,在 app/routes 文件夹中创建一个名为 note.routes.js 的新文件,内容如下:

module.exports = (app) => {
    const notes = require('../controllers/note.controller.js');

    // Create a new Note
    app.post('/notes', notes.create);

    // Retrieve all Notes
    app.get('/notes', notes.findAll);

    // Retrieve a single Note with noteId
    app.get('/notes/:noteId', notes.findOne);

    // Update a Note with noteId
    app.put('/notes/:noteId', notes.update);

    // Delete a Note with noteId
    app.delete('/notes/:noteId', notes.delete);
}

请注意,我们为 note.controller.js 文件添加了 require 语句。我们将定义控制oller 文件在下一节。控制器将包含处理所有 CRUD 操作的方法。

在定义控制器之前,让我们首先在 server.js 中包含路由。在 server.js 文件中的 app.listen() 行之前添加以下 require 语句。

// ........

// Require Notes routes
require('./app/routes/note.routes.js')(app);

// ........

如果你现在运行服务器,你会得到以下错误 -

$ node server.js
module.js:472
    throw err;
    ^

Error: Cannot find module '../controllers/note.controller.js'

这是因为我们还没有定义控制器。让我们现在就这样做。

编写控制器函数

app 文件夹中创建一个名为 controllers 的新文件夹,然后在 app/controllers 文件夹中创建一个名为 note.controller.js 的新文件,内容如下:

const Note = require('../models/note.model.js');

// Create and Save a new Note
exports.create = (req, res) => {

};

// Retrieve and return all notes from the database.
exports.findAll = (req, res) => {

};

// Find a single note with a noteId
exports.findOne = (req, res) => {

};

// Update a note identified by the noteId in the request
exports.update = (req, res) => {

};

// Delete a note with the specified noteId in the request
exports.delete = (req, res) => {

};

现在我们来一一看看上述控制器功能的实现——

创建新笔记
// Create and Save a new Note
exports.create = (req, res) => {
    // Validate request
    if(!req.body.content) {
        return res.status(400).send({
            message: "Note content can not be empty"
        });
    }

    // Create a Note
    const note = new Note({
        title: req.body.title || "Untitled Note", 
        content: req.body.content
    });

    // Save Note in the database
    note.save()
    .then(data => {
        res.send(data);
    }).catch(err => {
        res.status(500).send({
            message: err.message || "Some error occurred while creating the Note."
        });
    });
};
检索所有笔记
// Retrieve and return all notes from the database.
exports.findAll = (req, res) => {
    Note.find()
    .then(notes => {
        res.send(notes);
    }).catch(err => {
        res.status(500).send({
            message: err.message || "Some error occurred while retrieving notes."
        });
    });
};
检索单个笔记
// Find a single note with a noteId
exports.findOne = (req, res) => {
    Note.findById(req.params.noteId)
    .then(note => {
        if(!note) {
            return res.status(404).send({
                message: "Note not found with id " + req.params.noteId
            });            
        }
        res.send(note);
    }).catch(err => {
        if(err.kind === 'ObjectId') {
            return res.status(404).send({
                message: "Note not found with id " + req.params.noteId
            });                
        }
        return res.status(500).send({
            message: "Error retrieving note with id " + req.params.noteId
        });
    });
};
更新注释
// Update a note identified by the noteId in the request
exports.update = (req, res) => {
    // Validate Request
    if(!req.body.content) {
        return res.status(400).send({
            message: "Note content can not be empty"
        });
    }

    // Find note and update it with the request body
    Note.findByIdAndUpdate(req.params.noteId, {
        title: req.body.title || "Untitled Note",
        content: req.body.content
    }, {new: true})
    .then(note => {
        if(!note) {
            return res.status(404).send({
                message: "Note not found with id " + req.params.noteId
            });
        }
        res.send(note);
    }).catch(err => {
        if(err.kind === 'ObjectId') {
            return res.status(404).send({
                message: "Note not found with id " + req.params.noteId
            });                
        }
        return res.status(500).send({
            message: "Error updating note with id " + req.params.noteId
        });
    });
};

findByIdAndUpdate() 方法中的 {new: true} 选项用于将修改后的文档返回给 then() 函数而不是原始文档。

删除笔记
// Delete a note with the specified noteId in the request
exports.delete = (req, res) => {
    Note.findByIdAndRemove(req.params.noteId)
    .then(note => {
        if(!note) {
            return res.status(404).send({
                message: "Note not found with id " + req.params.noteId
            });
        }
        res.send({message: "Note deleted successfully!"});
    }).catch(err => {
        if(err.kind === 'ObjectId' || err.name === 'NotFound') {
            return res.status(404).send({
                message: "Note not found with id " + req.params.noteId
            });                
        }
        return res.status(500).send({
            message: "Could not delete note with id " + req.params.noteId
        });
    });
};

您可以在 Mongoose 的官方文档中查看我们在上述 API 中使用的所有方法的文档 -

*猫鼬保存()
*猫鼬查找()

  • 猫鼬 findById()
  • 猫鼬 findByIdAndUpdate()
  • 猫鼬 findByIdAndRemove()

测试我们的 API

现在让我们使用 postman 一一测试所有 API。

使用 POST /notes API 创建新笔记

使用 GET /notes API 检索所有笔记

使用 GET /notes/:noteId API 检索单个笔记

使用 PUT /notes/:noteId API 更新笔记

使用 DELETE /notes/:noteId API 删除笔记

相关文章