使用 Node、Express 和 MongoDB 构建 REST API!结论

2025-05-24

使用 Node、Express 和 MongoDB 构建 REST API!

结论

在这个项目中,我们将创建一种方式,方便用户订阅、更新、检索和删除 YouTube 帐户的数据。我们将编写一个 REST API 来实现这一点,该 API 允许用户与我们的 YouTube 数据库进行交互,具体方法是定义数据库接收哪些信息,以及如何根据用户的需要操作这些数据。

非常感谢Web Dev Simplified为我传授的知识,帮助我创建了本教程。如果您希望观看视频演示,我强烈建议您点击此处查看 Web Dev Simplified 的教程。

我的 GITHUB 仓库

如果您遇到困难或认为自己做错了什么,无法弄清楚,请参阅我已完成的应用程序的 Github Repo:https://github.com/Beznet/node-api

项目和依赖项设置

重要前提:在开始本教程之前,请确保您的计算机上已安装并设置好 MongoDB。以下是 MongoDB 官网提供的指南链接:MongoDB 安装

首先,打开终端并为该项目创建一个新目录。现在在终端中输入npm initstart,并在每个问题后按 ENTER 键,将所有字段暂时留空。接下来我们要安装ExpressMongoose

npm i express mongoose

然后,一旦这两个安装完成,我们还需要安装dotenvnodemon输入:

npm i --save-dev dotenv nodemon

注意:上面的 --save-dev 将保存仅开发依赖项,而不会将其保存到生产中

dotenv将允许我们从文件中提取环境变量.env,并且 nodemon 将在每次保存时更新我们的本地服务器

我们之前运行时,npm init它创建了一个package.json文件。在这个文件的脚本下,我们想用我们自己的脚本替换那个“测试”脚本,该脚本启动我们的服务器nodemon

"scripts": {
  "devStart": "nodemon server.js"
}
Enter fullscreen mode Exit fullscreen mode

设置我们的服务器

好的,现在我们来创建第一个文件,名为server.js。创建完成后,我们需要在文件顶部包含项目所需的所有依赖项:

const express = require('express')
const app = express()
const mongoose = require('mongoose')
Enter fullscreen mode Exit fullscreen mode

当我们想要测试并确保我们的服务器正常工作时,我们将运行此函数来监听端口 3000,并在成功时记录一个字符串:

app.listen(3000, () => console.log('server started'))
Enter fullscreen mode Exit fullscreen mode

此时我们的 server.js 文件应该如下所示:

const express = require('express')
const app = express()
const mongoose = require('mongoose')

app.listen(3000, () => console.log('server started'))
Enter fullscreen mode Exit fullscreen mode

连接到我们的数据库

文件中接下来的这段代码是server.js关于mongoose.connect如何连接数据库的。我会逐行解释:

const express = require('express')
const app = express()
const mongoose = require('mongoose')

mongoose.connect(process.env.DATABASE_URL, { useNewUrlParser: true })
const db = mongoose.connection
db.on('error', (error) => console.error(error))
db.once('open', () => console.log('connected to database'))

app.listen(3000, () => console.log('server started'))
Enter fullscreen mode Exit fullscreen mode

第一行允许我们使用 Mongoose 连接到数据库。你可能想知道这DATABASE_URL是什么,这就是我们想要的数据库位置,我已经在.env文件中定义了。如果你还没有创建.env文件,现在就可以DATABASE_URL在那里设置:

// .env file

DATABASE_URL=mongodb://localhost/subscribers
Enter fullscreen mode Exit fullscreen mode

DATABASE_URL定义好之后,我们.env回到server.js文件。现在,为了在.env文件中引用变量,我们需要dotenv在 server.js 文件顶部引入这个包:

require('dotenv').config()
Enter fullscreen mode Exit fullscreen mode

在我们收到所需的包裹后……

mongoose.connect(process.env.DATABASE_URL, { useNewUrlParser: true })
Enter fullscreen mode Exit fullscreen mode

...现在可以正常运行。

接下来,我们设置了dbmongoose.connection以便以更简单的语法方式引用数据库。接下来,我们定义了当数据库遇到错误时会发生什么,即记录error本身。如果没有错误,我们希望将 的字符串记录connected to database到终端。

好啦!内容有点多。所以,为了把所有内容整合在一起,我们的server.js文件现在应该像这样:

require('dotenv').config()

const express = require('express')
const app = express()
const mongoose = require('mongoose')

mongoose.connect(process.env.DATABASE_URL, { useNewUrlParser: true })
const db = mongoose.connection
db.on('error', (error) => console.error(error))
db.once('open', () => console.log('connected to database'))

app.listen(3000, () => console.log('server started'))
Enter fullscreen mode Exit fullscreen mode

让我们测试我们的数据库连接!

现在,我们可以测试一下数据库连接,确保一切正常。在终端中,输入以下命令启动数据库mongod,然后在另一个终端选项卡中输入以下命令启动服务器npm run devStart。如果一切顺利,启动服务器后应该会收到以下消息:

太棒了!我们已经成功启动了服务器,数据库似乎可以正常运行了。

设置我们的服务器以接受 JSON

在同一个server.js文件中,我们想告诉 Express 它应该接受 JSON。让我们将这行代码放在“数据库已打开”代码行和“监听 3000 端口”代码行之间:

...
db.once('open', () => console.log('connected to database'))

app.use(express.json())

app.listen(3005, () => console.log('server started'))
...
Enter fullscreen mode Exit fullscreen mode

.use是一个中间件,它允许你在服务器收到请求时、但在请求传递到路由之前运行代码。因此,在本例中,我们告诉 Express 接受 JSON 作为数据格式。

创建我们的路由文件夹和文件

让我们为路由创建一个名为 的新目录routes,然后在该目录中创建一个名为 的文件subscribers.js。在这个文件中,我们将定义服务器在收到 GET、POST 或 PATCH 请求时应如何处理数据。

但在开始创建这些之前,让我们先回到我们的server.js文件,告诉服务器我们现在有了需要处理和使用的路由。接下来的两行代码实际上是我们server.js文件所需的最后几行。

const subscribersRouter = require('./routes/subscribers')
app.use('/subscribers', subscribersRouter)
Enter fullscreen mode Exit fullscreen mode

server.js这是添加了新代码行的完整文件:

require('dotenv').config()

const express = require('express')
const app = express()
const mongoose = require('mongoose')

mongoose.connect(process.env.DATABASE_URL, { useNewUrlParser: true })
const db = mongoose.connection
db.on('error', (error) => console.error(error))
db.once('open', () => console.log('connected to database'))

app.use(express.json())

const subscribersRouter = require('./routes/subscribers')
app.use('/subscribers', subscribersRouter)

app.listen(3005, () => console.log('server started'))
Enter fullscreen mode Exit fullscreen mode

如果有任何缺失或错误,现在是一个很好的检查点,确保你已更新上述所有内容。为自己能走到这一步点个赞!接下来我们开始讲解有趣的内容……

设置我们的路线

现在我们的服务器文件已全部设置完毕,让我们切换到新的subscribers.js路由文件。首先,我们需要引入 Express,并express.router()在名为 的变量上定义一个函数router。同时,我们也在最底部添加模块导出函数:

const express = require('express')
const router = express.Router()

module.exports = router
Enter fullscreen mode Exit fullscreen mode

在开始编写代码之前,我们先来了解一下我们到底想用路由做什么。由于我们想在 YouTube 上查看并人为地创建新的订阅者,因此我们需要以下标准:

  • 获取所有订阅者的路线
  • 获取一个订阅者的路线
  • 创建一个订阅者的路线
  • 更新一个订阅者的路由
  • 删除一个订阅者的路由

现在让我们根据 GET、POST 还是 PATCH 请求,从基本框架开始上面的每个要点:

const express = require('express')
const router = express.Router()

// Get all subscribers
router.get('/', (req, res) => {
})

// Get one subscriber
router.get('/:id', (req, res) => {
})

// Create one subscriber
router.post('/', (req, res) => {
})

// Update one subscriber
router.patch('/:id', (req, res) => {
})

// Delete one subscriber
router.delete('/:id', (req, res) => {
})

module.exports = router
Enter fullscreen mode Exit fullscreen mode

GET、POST 和 DELETE 方法看起来应该很熟悉,但如果不熟悉的话,我们来稍微复习一下。唯一可能看起来有点奇怪的是 PATCH 方法。这里使用 PATCH 方法而不是更传统的 PUT 方法,因为我们只想用它来更新订阅者的部分信息,而不是所有信息。

您可能还注意到,我们/:id在大多数参数中都包含了 。这适用于请求对单个订阅者执行操作的路由,因此我们需要该订阅者的唯一 ID。

测试我们的 API

让我们暂时放下路由,用目前已有的内容测试一下我们的 API。在“获取所有订阅者”路由中,我们向服务器发送文本:

// Get all subscribers

router.get('/', (req, res) => {
   res.send('Hello World')
})
Enter fullscreen mode Exit fullscreen mode

现在,为了测试我们的 API,我将使用一个名为REST Client的 Visual Studio Code 扩展。如果您没有 VS Code,那么您可以使用另一个名为Postman的程序,它也有助于测试 API。在本教程中,我将仅使用 VS Code 中的 REST Client。

安装 REST 客户端扩展后,我们在文件夹中创建一个新文件,routes用于运行测试并将其命名为route.rest。该文件必须以 结尾,.rest否则将无法与 REST 客户端正常工作。

太好了,现在让我们在文件中编写一个对服务器的测试 GET 调用route.rest

GET http://localhost:3000/subscribers
Enter fullscreen mode Exit fullscreen mode

确保输入了/subscribers3000 之后的内容。现在,如果你将鼠标悬停在刚刚输入的那一行上方,你应该会看到“发送请求”出现在其上方。点击它,然后在屏幕右侧查看结果。如果一切顺利,结果应该如下所示:

在第 9 行,我们可以看到服务器返回了“hello world”。这意味着我们的 API 正常工作了!好了,到目前为止我们已经做了很多,让我们稍事休息,然后开始构建模型。

制作模型

让我们继续设置我们的模型以及模型内部的模式。模式是我们的应用程序定义数据的形式,同时也用于在 MongoDB 中设置文档。如果这听起来有点令人困惑,那么一旦我们了解了发生了什么,就会更容易理解。

首先,我们先创建一个名为 的新文件夹models。在此文件夹内,我们再创建一个名为 的新文件subscriber.js。请注意,我们将此文件命名为单数“subscriber”,而不是复数“subscribers”。我们的想法是,该模型将处理每个订阅者如何在个人层面上查看数据库。“subscribers”路由有时会处理多个订阅者的请求,例如“获取所有订阅者”路由。这一点值得一提,因为在项目中命名文件时,措辞非常重要。

在这个新文件中,我们首先需要 Mongoose,因为我们将使用它们的模式模型:

const mongoose = require('mongoose')
Enter fullscreen mode Exit fullscreen mode

在我们需要 Mongoose 之后,我们将开始定义我们的模式

const mongoose = require('mongoose')

const subscriberSchema = new mongoose.Schema({})
Enter fullscreen mode Exit fullscreen mode

这个 JavaScript 对象内部包含了我们订阅者不同属性的所有键。这些键包括namesubscribedChannelsubscribeDate。我们本质上想告诉数据库每个键的期望值,例如它们的类型、是否必需以及是否应该应用默认值。

const mongoose = require('mongoose')

const subscriberSchema = new mongoose.Schema({
  name: {
    type: String,
    required: true
  },
  subscribedChannel: {
    type: String,
    required: true
  },
  subscribeDate: {
    type: Date,
    required: true,
    default: Date.now
  }
})
Enter fullscreen mode Exit fullscreen mode

type和属性的含义required应该不言自明。它们定义了预期的架构类型(在本例中为字符串和日期),以及在为新订阅者输入信息时是否需要该键。

需要注意的是subscribeDate,我们将类型设置为 Date 而不是 String,因为我们需要用户输入日期。如果没有提供日期,我们会使用 将其默认为当前日期Date.now

接下来,我们要在模式中编写的最后一行代码是module.exports。这将允许我们使用模式来使用数据库并与之交互。Mongoose 有一种特殊的导出模型的方式,mongoose.model()它利用两个属性:

// exporting our subscriber schema

module.exports = mongoose.model('Subscriber', subscriberSchema)
Enter fullscreen mode Exit fullscreen mode

“订阅者”是我们想要在数据库中赋予模型的名称,然后下一个是与该模型相对应的模式,即我们的subscriberSchema

这就是我们的模型!让我们看一下完成的模式,以确保我们已经掌握了所有内容:

const mongoose = require('mongoose')

const subscriberSchema = new mongoose.Schema({
  name: {
    type: String,
    required: true
  },
  subscribedChannel: {
    type: String,
    required: true
  },
  subscribeDate: {
    type: Date,
    required: true,
    default: Date.now
  }
})

module.exports = mongoose.model('Subscriber', subscriberSchema)
Enter fullscreen mode Exit fullscreen mode

路线 – 创建并获取订阅者

现在我们已经为我们的数据库设置了模型和模式,让subscribers.js我们在下面的路由文件中引用它router

const express = require('express')
const router = express.Router()
const Subscriber = require('../models/subscriber')
Enter fullscreen mode Exit fullscreen mode

现在我们可以从上次中断的地方继续我们的路线,我们为每个路线编写了一个 shell:

// Getting all subscribers
router.get('/', (req, res) => {
   res.send('Hello World')
})

// Getting one subscriber
router.get('/:id', (req, res) => {
})

// Creating one subscriber
router.post('/', (req, res) => {
})

// Updating one subscriber
router.patch('/:id', (req, res) => {
})

// Deleting one subscriber
router.delete('/:id', (req, res) => {
})
Enter fullscreen mode Exit fullscreen mode

当我们向服务器发送“Hello World”时,我们有之前的测试响应,但我们可以继续删除它,因为我们实际上想告诉该路由获取所有订阅者。

在我们摆脱旧res.send('Hello World')行之后,我们需要做的第一件事就是用 try/catch 语句将函数包装在承诺中:

// Get all subscribers

router.get('/', async (req, res) => {
  try {

  } catch () {

  }
})
Enter fullscreen mode Exit fullscreen mode

在我们的语句中,try我们想要从模型中获取所有订阅者。因此,我们需要为该模型设置一个名为“subscribers”的新变量,并将一个.find()方法应用于“Subscriber”模型。

// Get all subscribers

router.get('/', async (req, res) => {
  try {
    const subscribers = await Subscriber.find()
  } catch () {

  }
})
Enter fullscreen mode Exit fullscreen mode

顾名思义,find()Mongoose 方法的工作原理是返回所有符合其条件的关联订阅者对象。由于我们要返回所有订阅者,因此括号内的内容无需填写,因为我们想要所有订阅者:

subscribers在该行之后,我们希望以 JSON 形式发送我们刚刚创建的变量的数据响应:

// Get all subscribers

router.get('/', async (req, res) => {
  try {
    const subscribers = await Subscriber.find()
    res.json(subscribers)
  } catch () {

  }
})
Enter fullscreen mode Exit fullscreen mode

最后,在我们的catch语句中,我们只想捕获可能发生的任何错误,并将其作为 JSON 格式的 500 错误发送给用户:

// Get all subscribers

router.get('/', async (req, res) => {
  try {
    const subscribers = await Subscriber.find()
    res.json(subscribers)
  } catch (err) {
    res.status(500).json({ message: err.message })
  }
})
Enter fullscreen mode Exit fullscreen mode

现在我们已经有了将数据库中所有订阅者发送给我们的路由,接下来我们需要编写一个代码,将订阅者添加到数据库中。因此,让我们转到“创建订阅者”路由,以便输入订阅者的数据:

// Create one subscriber

router.post('/', async (req, res) => {
  const subscriber = new Subscriber({
    name: req.body.name,
    subscribedChannel: req.body.subscribedChannel
  })

  try {
    const newSubscriber = await subscriber.save()
    res.status(201).json(newSubscriber)
  } catch (err) {
    res.status(400).json({ message: err.message })
  }
})
Enter fullscreen mode Exit fullscreen mode

您可以看到,它与“获取所有订阅者”路由有些相似,但有一些重要的区别。首先,我们不再对数据库执行 GET 调用,而是使用 POST 调用,这样我们就可以向数据库推送数据。

在此行:

const subscriber = new Subscriber({...

Subscriber我们正在创建一个变量,该变量将被赋值给之前创建的模型中的new 。如果您还记得的话,我们需要为新订阅者添加namesubscribedChannel和属性。subscribeDate

接下来的两行代码:

name: req.body.name,
subscribedChannel: req.body.subscribedChannel

我们正在告诉路由保存用户输入的新订阅者name属性和subscribedChannel属性所发出的请求。我们的subscribeDate不需要定义,因为它会自动默认为该数据库条目的日期/时间。

try语句catch看起来应该很熟悉。我们改用.save()Mongoose 的方法,而不是 ,find()因为这样我们就可以告诉数据库,我们希望它保存用户通过此路由器函数传递给我们的信息。

最后:

...
res.status(201).json(newSubscriber)
} catch (err) {
res.status(400).json({ message: err.message })
}

我们向用户发送一个成功状态为 201 的响应,并将新的订阅者以 JSON 格式返回给我们。问题类似于“获取所有订阅者”路由,只不过我们传递了一个400 错误,因为如果用户传递了错误的数据,就会报错。

让我们创建并获取我们的第一个订阅者!

至此,我们已经创建了模型和两个路由,它们允许我们创建订阅者,然后从数据库中调用该订阅者的信息。让我们回到文件route.rest并创建第一个用户:

GET http://localhost:3000/subscribers

###

POST http://localhost:3000/subscribers
Content-Type: application/json

{
  "name": "Robert",
  "subscribedChannel": "Bennetts Channel"
}
Enter fullscreen mode Exit fullscreen mode

使用 REST 客户端,我们需要使用第 3 行两个语句之间的三个标签来分隔不同的测试请求。

我们的第一个请求应该与之前完全相同,所以这里唯一的不同是我们新的 POST 请求,它允许我们创建一个新的订阅者,并指定他们的名字(我这里是 Robert)和他们订阅的频道(我的!)。现在让我们运行 POST 请求,看看会得到什么:

如果一切顺利,点击“发送请求”后的响应应该如上所示。我们可以看到,在最顶部收到了 201 成功状态,而在底部则收到了包含我们刚刚输入的所有信息的 Subscriber 对象。

再次强调,subscribeDate它会自动设置为创建日期,因此我们无需手动设置。现在,让我们使用“获取所有订阅者”请求,并确保它返回 Robert 的信息:

我们的响应看起来类似于我们的创建订阅者响应,因为我们的数据库中只有一个用户,但如果您创建多个订阅者,那么这将为您填充所有订阅者。

中间件是什么?中间件!

我们已经到了最后冲刺阶段!最后几件事就是完成删除、更新和获取一个订阅者的路由,这样我们的 REST API 就完成了!

最后三条路由有一个共同点,就是获取特定用户的 ID。我们不用把这部分代码写三遍,只需将其放在单独的函数中,并在 Mongoose 的 GET/PATCH/POST 语句中将其作为中间件调用即可。让我们将这个中间件函数放在getSubscriber我们代码行之前module.exports = router

async function getSubscriber(req, res, next) {
  try {
    subscriber = await Subscriber.findById(req.params.id)
    if (subscriber == null) {
      return res.status(404).json({ message: 'Cant find subscriber'})
    }
  } catch(err){
    return res.status(500).json({ message: err.message })
  }

  res.subscriber = subscriber
  next()
}
Enter fullscreen mode Exit fullscreen mode

这里有很多内容,让我们分解一下。第一行看起来应该很熟悉,除了那个名为 的新属性next。基本上,当被调用时,它告诉函数执行进入代码的下一部分,也就是该函数将被添加到的next路由函数。getSubscriber

我们的tryandcatch语句与其他路由一样打开。然后,我们在第 3 行定义订阅者,相当于我们的订阅者模型对象,我们将使用该findById方法查找与用户从父路由传入的 ID 对应的订阅者。这会将 设置subscriber为等于该 ID 的对象。

附注:这部分可能有点令人困惑,但请耐心等待,直到我们讲到下面的更新/删除/获取一个路由。当我们实际操作时,我会更清楚地解释。

一旦我们将subscriber它设置为模型对象,我们就会用一个if语句来检查该订阅者是否存在null。如果订阅者不存在,我们就抛出 404 错误。然后,我们catch会进行常见的错误检查,并在出现以下情况时向用户返回 500 状态码:

最后,我们只剩下中间件函数的最后两行代码:

res.subscriber = subscriber
next()

res.subscriber会在响应对象上设置一个变量,该变量的值等于我们的订阅者对象。这很有用,这样我们就不用再写同样的代码了,只需在这个函数中引用即可。最后,在其他所有操作都执行完成后,res.subscriber我们使用该函数来告诉它转到实际的请求。next()getSubscriber

现在我们已经完成了中间件功能,让我们将其添加到我们的删除、更新和获取路由中:

// Get one subscriber
router.get('/:id', getSubscriber, (req, res) => {
})

// Update one subscriber
router.patch('/:id', getSubscriber, async (req, res) => {
})

// Delete one subscriber
router.delete('/:id', getSubscriber, async (req, res) => {
})
Enter fullscreen mode Exit fullscreen mode

路线 – 获取一个订阅者

我们用中间件完成了最后三个路由的大部分繁重工作,为此我们感到很高兴。让我们从“获取一个”路由开始:

// Get One Subscriber

router.get('/:id', getSubscriber, (req, res) => {
  res.json(res.subscriber)
})
Enter fullscreen mode Exit fullscreen mode

看看这看起来多么简单。我们只需要向用户发送一个 JSON 格式的响应,其中包含res.subscriber我们在中间件函数中定义的返回特定订阅者信息的 。我们可以快速测试这个新路由,以确保我们的getSubscriber中间件函数和我们创建的新路由能够正常工作。

让我们跳回到我们的route.rest文件并使用我们的创建订阅者请求创建一个新的订阅者,以便我们可以获取该订阅者的 ID:

好了,我们创建了一个新的订阅者,并将其命名为 Bob。我们可以看到,他的名字上方有一个与其对象关联的长 ID。我想保留这个 ID,这样在编写新的 GET 路由时,就可以通过他的 ID 来调用 Bob。我们可以将它放在“获取所有订阅者”请求的下方:

GET http://localhost:3000/subscribers

###

GET http://localhost:3000/subscribers/5d3ce4ef1b5de0b79d3443b9

###

POST http://localhost:3000/subscribers
Content-Type: application/json

{
  "name": "bob",
  "subscribedChannel": "Bennetts Channel"
}
Enter fullscreen mode Exit fullscreen mode

在第 5 行我们将创建新的测试请求,因此请输入您新创建的用户的 ID(您的 ID 与上面的不同)并单击“发送请求”:

如果一切顺利,我们应该不会在右侧看到任何变化,因为我们只是调用了刚刚创建的用户。给自己点个赞,你的中间件函数和 Get One 路由成功了!

路线 – 删除订户

现在我们知道我们的中间件正在完成它的工作,让我们切换回我们的subscribers.js路由文件并从 Delete 开始完成最后两个路由:

// Delete one subscriber

router.delete('/:id', getSubscriber, async (req, res) => {
  try {
    await res.subscriber.remove()
    res.json({ message: 'Deleted This Subscriber' })
  } catch(err) {
    res.status(500).json({ message: err.message })
  }
})
Enter fullscreen mode Exit fullscreen mode

我们打开语句,然后在设置之前try插入运算符,然后使用该方法删除对象所设置的订阅者。然后,我们希望通过传递 JSON 格式的响应消息来告诉用户我们已成功删除订阅者:awaitres.subscriberremove()res.subscriber

res.json({ message: 'Deleted This Subscriber' })

与往常一样,我们希望catch在发生错误时向用户发送相应的错误信息。这就是删除操作的全部内容!

路线 – 更新订户

为了使这个应用程序完全正常运行,我们需要编写的最后一项就是更新订阅者路由!在开始编写代码之前,我们先来大致了解一下在这种情况下更新是如何进行的:

  • 用户仅更新名称
  • 用户仅更新频道
  • 用户更新姓名和频道
  • 或者他们搞砸了,然后抛出一个错误

我们的需求需要我们本质上检查一下是否有任何更改,如果有,则进行适当的更新。现在来看看代码:

// Update Subscriber

router.patch('/:id', getSubscriber, async (req, res) => {
  if (req.body.name != null) {
    res.subscriber.name = req.body.name
  }

  if (req.body.subscribedChannel != null) {
    res.subscriber.subscribedChannel = req.body.subscribedChannel
  }
  try {
    const updatedSubscriber = await res.subscriber.save()
    res.json(updatedSubscriber)
  } catch {
    res.status(400).json({ message: err.message })
  }

})
Enter fullscreen mode Exit fullscreen mode

我们从 PATCH 方法开始我们的函数,我们在最初定义路由的 shell 时讨论过这个方法。现在您可以看到我们if在函数中添加了两个语句。第一个 if 语句检查来自body用户请求的 name 是否不等于null。这是一个重要的检查,因为如果等于null,则意味着用户没有通过我们的路由函数传递任何关于 name 的数据。如果传递了,那么我们转到这一行:

res.subscriber.name = req.body.name

我们从哪里设置订阅者的姓名res.subscriber,并将该姓名设置为用户从其请求中传递的新姓名。

同样的逻辑也适用于此:

res.subscriber.subscribedChannel = req.body.subscribedChannel

我们正在检查用户是否更新了,如果是,则我们按照用户的请求subscribedChannel执行相同的顺序将当前更新更改为新更新。subscribedChannel

完成这些if语句检查后,我们需要告诉函数将这些新的更改保存到数据库中。这很容易在try语句中完成,我们获取res.subscriber具有新名称和/或新通道的对象,然后save()在名为 的新变量中添加方法updatedSubscriber。然后,我们希望将这个新updatedSubscriber对象以 JSON 格式传递给用户:

try {
const updatedSubscriber = await res.subscriber.save()
res.json(updatedSubscriber)
}

这实际上就是我们在subscribers.js路由文件中需要的所有内容,所以让我们在这里暂停一下,确保到目前为止所有内容都已完成。在进行下面的最终测试之前,请前往我的GitHub 仓库,并确保你的代码与我提供的内容完全一致。

最终考验

我们已经完成了最后两条路线,让我们进入我们的route.rest文件并测试这些坏男孩并确保它们正常工作。

我们的删除请求和获取一个订阅者路由一样简单,只不过我们用 DELETE 请求代替了 GET 请求。因此,获取数据库中某个订阅者的 ID,然后创建测试路由:

###

DELETE http://localhost:3000/subscribers/5d3e0db7cb4be0bfc4c25ff9
Enter fullscreen mode Exit fullscreen mode

现在让我们点击“发送请求”并查看我们的用户是否被成功删除:

太棒了!现在,我们在右侧看到了“已删除此订阅者”的消息,这意味着我们成功了。现在,如果你拿着刚刚删除的那个 ID,尝试使用“获取一个订阅者”请求来获取它,它会告诉我们找不到该订阅者,因为该订阅者已不存在于我们的数据库中:

我们的最后一个请求是使用 Update 路由更新数据库中现有订阅者的信息。由于我们刚刚删除了最后一个订阅者,因此我们创建一个新的订阅者,并使用 PATCH 编写更新请求:

###

PATCH http://localhost:3000/subscribers/5d3e144ecb4be0bfc4c25ffa
Content-Type: application/json 

{
  "name": "Tommy"
}
Enter fullscreen mode Exit fullscreen mode

我在运行上述 PATCH 请求之前刚刚创建了一个新的订阅者,并将其命名为 Lizzy:

好的,如果我们运行上述 PATCH 请求,我们应该看到 Lizzy 的名字更改为 Tommy:

如果一切顺利的话,我们就能成功地将 Lizzy 的名字更新为 Tommy。

结论

伙计们,我们成功了!真心希望本教程对你们有所帮助。我们讲解了很多内容,所以如果你们感到不知所措,完全可以理解。不过,我们刚刚编写了一段非常棒的后端代码,它可以转化为许多不同的实际应用。所以,非常感谢你们完成了所有教程!

如果你遇到困难或发现值得分享的内容,请在下方留言。也欢迎关注我的TwitterYoutube,我会定期更新文章。祝大家编程愉快!

原文发表于此处

文章来源:https://dev.to/beznet/build-a-rest-api-with-node-express-mongodb-4ho4
PREV
在从事全职工作的同时学习编程
NEXT
5 种紧跟科技发展的工具