MongoDB 数据库结合 Web 服务 - 图1
在这次演示中,我们来搭建一个支持 MongoDB 数据库 CRUD 操作的 Web 接口服务,用来进行博客文章的管理。

通过本实战案例,希望你会对数据库及 Web 开发有更深一步的理解。

接口设计

基于 RESTful 接口规范。

创建文章

  • 请求路径:POST /articles
  • 请求参数:Body
    • title 标题
    • description 简介
    • body 内容
    • tagList 标签列表
  • 数据格式:application/json

请求体示例:
{
“article”: {
“title”: “How to train your dragon”,
“description”: “Ever wonder how?”,
“body”: “You have to believe”,
“tagList”: [“reactjs”, “angularjs”, “dragons”]
}
}
image.png
image.png
后端返回成功数据示例:

  • 状态码:201
  • 响应数据:

{
“article”: {
“_id”: 123,
“title”: “How to train your dragon”,
“description”: “Ever wonder how?”,
“body”: “It takes a Jacobian”,
“tagList”: [“dragons”, “training”],
“createdAt”: “2016-02-18T03:22:56.637Z”,
“updatedAt”: “2016-02-18T03:48:35.824Z”
}
}

获取文章列表

  • 请求路径:GET /articles
  • 请求参数(Query)
    • _page:页码
    • _size:每页大小

响应数据示例:

  • 状态码:200
  • 响应数据:

{
“articles”:[
{
“_id”: “how-to-train-your-dragon”,
“title”: “How to train your dragon”,
“description”: “Ever wonder how?”,
“body”: “It takes a Jacobian”,
“tagList”: [“dragons”, “training”],
“createdAt”: “2016-02-18T03:22:56.637Z”,
“updatedAt”: “2016-02-18T03:48:35.824Z”
},
{
“_id”: “how-to-train-your-dragon-2”,
“title”: “How to train your dragon 2”,
“description”: “So toothless”,
“body”: “It a dragon”,
“tagList”: [“dragons”, “training”],
“createdAt”: “2016-02-18T03:22:56.637Z”,
“updatedAt”: “2016-02-18T03:48:35.824Z”
}
],
“articlesCount”: 2
}

获取单个文章

  • 请求路径:GET /articles/:id

响应数据示例:

  • 状态码:200
  • 响应数据:

{
“article”: {
“_id”: “dsa7dsa”,
“title”: “How to train your dragon”,
“description”: “Ever wonder how?”,
“body”: “It takes a Jacobian”,
“tagList”: [“dragons”, “training”],
“createdAt”: “2016-02-18T03:22:56.637Z”,
“updatedAt”: “2016-02-18T03:48:35.824Z”
}
}

更新文章

  • 请求路径:PATCH /artilces/:id
  • 请求参数(Body)
    • title
    • description
    • body
    • tagList

请求体示例:

  • 状态码:201
  • 响应数据:

{
“article”: {
“title”: “Did you train your dragon?”
}
}
响应示例:
{
“article”: {
“_id”: 123,
“title”: “How to train your dragon”,
“description”: “Ever wonder how?”,
“body”: “It takes a Jacobian”,
“tagList”: [“dragons”, “training”],
“createdAt”: “2016-02-18T03:22:56.637Z”,
“updatedAt”: “2016-02-18T03:48:35.824Z”
}
}

删除文章

  • 接口路径:DELETE /articles/:id

响应数据:

  • 状态码:204
  • 数据:

{}

准备工作

  1. mkdir article-bed
  2. cd api-serve
  3. npm init -y
  4. npm i express mongodb

使用 Express 快速创建 Web 服务

  1. const express = require('express')
  2. const app = express()
  3. const port = 3000
  4. app.get('/', (req, res) => {
  5. res.send('Hello World!')
  6. })
  7. app.listen(port, () => {
  8. console.log(`Example app listening at http://localhost:${port}`)
  9. })

路由设计

  1. app.get('/', (req, res) => {
  2. res.send('Hello World!')
  3. })
  4. app.post('/articles', (req, res) => {
  5. res.send('post /articles')
  6. })
  7. app.get('/articles', (req, res) => {
  8. res.send('get /articles')
  9. })
  10. app.get('/articles/:id', (req, res) => {
  11. res.send('get /articles/:id')
  12. })
  13. app.patch('/articles/:id', (req, res) => {
  14. res.send('patch /articles/:id')
  15. })
  16. app.delete('/articles/:id', (req, res) => {
  17. res.send('delete /articles/:id')
  18. })

处理 Body 请求数据

  1. // 配置解析请求体数据 application/json
  2. // 它会把解析到的请求体数据放到 req.body 中
  3. // 注意:一定要在使用之前就挂载这个中间件
  4. app.use(express.json())

错误处理

配置 CORS

封装数据库操作模块

创建文章

  1. app.post('/articles', async (req, res, next) => {
  2. try {
  3. // 1. 获取客户端表单数据
  4. const { article } = req.body
  5. // 2. 数据验证
  6. if (!article || !article.title || !article.description || !article.body) {
  7. return res.status(422).json({
  8. error: '请求参数不符合规则要求'
  9. })
  10. }
  11. // 3. 把验证通过的数据插入数据库中
  12. // 成功 -> 发送成功响应
  13. // 失败 -> 发送失败响应
  14. await dbClient.connect()
  15. const collection = dbClient.db('test').collection('articles')
  16. article.createdAt = new Date()
  17. article.updatedAt = new Date()
  18. const ret = await collection.insertOne(article)
  19. article._id = ret.insertedId
  20. res.status(201).json({
  21. article
  22. })
  23. } catch (err) {
  24. // 由错误处理中间件统一处理
  25. next(err)
  26. // res.status(500).json({
  27. // error: err.message
  28. // })
  29. }
  30. })

获取文章列表

  1. app.get('/articles', async (req, res, next) => {
  2. try {
  3. let { _page = 1, _size = 10 } = req.query
  4. _page = Number.parseInt(_page)
  5. _size = Number.parseInt(_size)
  6. await dbClient.connect()
  7. const collection = dbClient.db('test').collection('articles')
  8. const ret = await collection
  9. .find() // 查询数据
  10. .skip((_page - 1) * _size) // 跳过多少条 10 1 0 2 10 3 20 n
  11. .limit(_size) // 拿多少条
  12. const articles = await ret.toArray()
  13. const articlesCount = await collection.countDocuments()
  14. res.status(200).json({
  15. articles,
  16. articlesCount
  17. })
  18. } catch (err) {
  19. next(err)
  20. }
  21. })

获取单个文章

  1. app.get('/articles/:id', async (req, res, next) => {
  2. try {
  3. await dbClient.connect()
  4. const collection = dbClient.db('test').collection('articles')
  5. const article = await collection.findOne({
  6. _id: ObjectID(req.params.id)
  7. })
  8. res.status(200).json({
  9. article
  10. })
  11. } catch (err) {
  12. next(err)
  13. }
  14. })

更新文章

  1. app.patch('/articles/:id', async (req, res, next) => {
  2. try {
  3. await dbClient.connect()
  4. const collection = dbClient.db('test').collection('articles')
  5. await collection.updateOne({
  6. _id: ObjectID(req.params.id)
  7. }, {
  8. $set: req.body.article
  9. })
  10. const article = await await collection.findOne({
  11. _id: ObjectID(req.params.id)
  12. })
  13. res.status(201).json({
  14. article
  15. })
  16. } catch (err) {
  17. next(err)
  18. }
  19. })

删除文章

  1. app.delete('/articles/:id', async (req, res, next) => {
  2. try {
  3. await dbClient.connect()
  4. const collection = dbClient.db('test').collection('articles')
  5. await collection.deleteOne({
  6. _id: ObjectID(req.params.id)
  7. })
  8. res.status(204).json({})
  9. } catch (err) {
  10. next(err)
  11. }
  12. })

上一篇

在 Node.js 中操作 MongoDB

下一篇

使用 mongoose 操作 MongoDB