
在这次演示中,我们来搭建一个支持 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"]}}
返回数据示例:
- 状态码: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
- 数据:
{}
准备工作
mkdir article-bedcd api-servenpm init -ynpm i express mongodb
使用 Express 快速创建 Web 服务
const express = require('express')const app = express()const port = 3000app.get('/', (req, res) => {res.send('Hello World!')})app.listen(port, () => {console.log(`Example app listening at http://localhost:${port}`)})
路由设计
app.get('/', (req, res) => {res.send('Hello World!')})app.post('/articles', (req, res) => {res.send('post /articles')})app.get('/articles', (req, res) => {res.send('get /articles')})app.get('/articles/:id', (req, res) => {res.send('get /articles/:id')})app.patch('/articles/:id', (req, res) => {res.send('patch /articles/:id')})app.delete('/articles/:id', (req, res) => {res.send('delete /articles/:id')})
处理 Body 请求数据
// 配置解析请求体数据 application/json// 它会把解析到的请求体数据放到 req.body 中// 注意:一定要在使用之前就挂载这个中间件app.use(express.json())
错误处理
配置 CORS
封装数据库操作模块
创建文章
app.post('/articles', async (req, res, next) => {try {// 1. 获取客户端表单数据const { article } = req.body// 2. 数据验证if (!article || !article.title || !article.description || !article.body) {return res.status(422).json({error: '请求参数不符合规则要求'})}// 3. 把验证通过的数据插入数据库中// 成功 -> 发送成功响应// 失败 -> 发送失败响应await dbClient.connect()const collection = dbClient.db('test').collection('articles')article.createdAt = new Date()article.updatedAt = new Date()const ret = await collection.insertOne(article)article._id = ret.insertedIdres.status(201).json({article})} catch (err) {// 由错误处理中间件统一处理next(err)// res.status(500).json({// error: err.message// })}})
获取文章列表
app.get('/articles', async (req, res, next) => {try {let { _page = 1, _size = 10 } = req.query_page = Number.parseInt(_page)_size = Number.parseInt(_size)await dbClient.connect()const collection = dbClient.db('test').collection('articles')const ret = await collection.find() // 查询数据.skip((_page - 1) * _size) // 跳过多少条 10 1 0 2 10 3 20 n.limit(_size) // 拿多少条const articles = await ret.toArray()const articlesCount = await collection.countDocuments()res.status(200).json({articles,articlesCount})} catch (err) {next(err)}})
获取单个文章
app.get('/articles/:id', async (req, res, next) => {try {await dbClient.connect()const collection = dbClient.db('test').collection('articles')const article = await collection.findOne({_id: ObjectID(req.params.id)})res.status(200).json({article})} catch (err) {next(err)}})
更新文章
app.patch('/articles/:id', async (req, res, next) => {try {await dbClient.connect()const collection = dbClient.db('test').collection('articles')await collection.updateOne({_id: ObjectID(req.params.id)}, {$set: req.body.article})const article = await await collection.findOne({_id: ObjectID(req.params.id)})res.status(201).json({article})} catch (err) {next(err)}})
删除文章
app.delete('/articles/:id', async (req, res, next) => {try {await dbClient.connect()const collection = dbClient.db('test').collection('articles')await collection.deleteOne({_id: ObjectID(req.params.id)})res.status(204).json({})} catch (err) {next(err)}})
