1.案例
通过创建一个简单的CURD接口服务,从而掌握Express的基本用法。 需求:实现对任务清单的CURD接口服务。
- 查询任务列表
GET /todos
- 根据ID查询单个任务
GET /todos/:id
- 添加任务
POST /todos
- 修改任务
PATCH /todos/:id
- 删除任务
DELETE /todos/:id
2.路由设计
路由设计代码,如下:
const express = require('express');
const app = express()
// 查询任务
app.get('/todos', (req, res) => {
res.send('get /todos')
})
// 查询单个任务
app.get('/todos/:id', (req, res) => {
//通过req.params来获取动态的路由地址
res.send(`get /todos/${req.params.id}`)
})
// 添加任务
app.post('/todos', (req, res) => {
res.send('post /todos')
})
// 修改任务
app.patch('/todos/:id', (req, res) => {
res.send(`patch /todos/${req.params.id}`)
})
// 删除任务
app.delete('/todos/:id', (req, res) => {
res.send(`delete /todos/${req.params.id}`)
})
app.listen(3000, () => {
console.log('server is running!!')
})
3.查询任务
3.1 新建一个db.json文件,用来存放数据,内容如下:
{
"todos": [
{
"id": 1,
"name": "降龙十八掌"
},
{
"id": 2,
"name": "独孤九剑"
},
{
"id": 3,
"name": "九阳神功"
}
],
"users": []
}
3.2 修改查询任务的代码,如下
const express = require('express');
const app = express()
const fs = require('fs')
// 查询任务
app.get('/todos', (req, res) => {
fs.readFile('db.json', 'utf-8', (err, data) => {
if (err) {
return res.status(500).json({
error: err.message
})
}
var db = JSON.parse(data)
res.status(200).json(db.todos)
})
})
// 查询单个任务
app.get('/todos/:id', (req, res) => {
res.send(`get /todos/${req.params.id}`)
})
// 添加任务
app.post('/todos', (req, res) => {
res.send('post /todos')
})
// 修改任务
app.patch('/todos/:id', (req, res) => {
res.send(`patch /todos/${req.params.id}`)
})
// 删除任务
app.delete('/todos/:id', (req, res) => {
res.send(`delete /todos/${req.params.id}`)
})
app.listen(3000, () => {
console.log('server is running!!')
})
思路:通过Nodejs的读文件功能,读取文件,返回的是字符串格式(注意设置成utf-8),然后,将json字符串转成json格式返给客户端。
4.查询单个数据
查询单个任务的代码,如下:
const express = require('express');
const app = express()
const fs = require('fs')
// 查询任务
app.get('/todos', (req, res) => {
fs.readFile('db.json', 'utf-8', (err, data) => {
if (err) {
return res.status(500).json({
error: err.message
})
}
var db = JSON.parse(data)
res.status(200).json(db.todos)
})
})
// 查询单个任务
app.get('/todos/:id', (req, res) => {
fs.readFile('db.json', 'utf-8', (err, data) => {
if (err) {
return res.status(500).json({
error: err.message
})
}
var db = JSON.parse(data)
var todo = db.todos.find(todo => todo.id.toString() === req.params.id);
if (!todo) {
return res.status(404).json({
data: 'not found'
})
}
res.status(200).json(todo)
})
})
// 添加任务
app.post('/todos', (req, res) => {
res.send('post /todos')
})
// 修改任务
app.patch('/todos/:id', (req, res) => {
res.send(`patch /todos/${req.params.id}`)
})
// 删除任务
app.delete('/todos/:id', (req, res) => {
res.send(`delete /todos/${req.params.id}`)
})
app.listen(3000, () => {
console.log('server is running!!')
})
思路:和查询全部数据的思路一样,查到全部数据之后,根据传过来的id和读取到的数据进行比较,这里要注意
地址栏获取的参数是字符串类型,json数据中的id是number类型,需要转换以下,然后,判断以下是否查到了数据,如果查到了返回该数据,如果没查到返回404,not fount
5.封装db模块
思考:考虑到目前查询全部数据的功能和查询单条数据的功能中,获取数据的代码都一样,我们可以对他们进行封装以下。
新建db.js,内容如下:
const fs = require('fs');
const { promisify } = require('util');
const path = require('path')
const readFile = promisify(fs.readFile)
const dbPath = path.join(__dirname, './db.json')
exports.getDb = async () => {
let data = await readFile(dbPath, 'utf8')
return JSON.parse(data)
}
promisify: 将异步回调的方法处理成promise
index.js文件,代码修改如下:
const express = require('express');
const app = express()
const fs = require('fs')
const { getDb } = require('./db')
// 查询任务
app.get('/todos', async (req, res) => {
try {
let db = await getDb();
res.status(200).json(db.todos);
} catch (err) {
res.status(500).json({
error: err.message
})
}
// fs.readFile('db.json', 'utf-8', (err, data) => {
// if (err) {
// return res.status(500).json({
// error: err.message
// })
// }
// var db = JSON.parse(data)
// res.status(200).json(db.todos)
// })
})
// 查询单个任务
app.get('/todos/:id', async (req, res) => {
try {
let db = await getDb();
let todo = db.todos.find(todo => todo.id.toString() === req.params.id);
if (!todo) {
return res.status(404).json({
data: 'not found'
})
}
res.status(200).json(todo)
} catch {
res.status(500).json({
error: err.message
})
}
// fs.readFile('db.json', 'utf-8', (err, data) => {
// if (err) {
// return res.status(500).json({
// error: err.message
// })
// }
// var db = JSON.parse(data)
// var todo = db.todos.find(todo => todo.id.toString() === req.params.id);
// if (!todo) {
// return res.status(404).json({
// data: 'not found'
// })
// }
// res.status(200).json(todo)
// })
})
// 添加任务
app.post('/todos', (req, res) => {
res.send('post /todos')
})
// 修改任务
app.patch('/todos/:id', (req, res) => {
res.send(`patch /todos/${req.params.id}`)
})
// 删除任务
app.delete('/todos/:id', (req, res) => {
res.send(`delete /todos/${req.params.id}`)
})
app.listen(3000, () => {
console.log('server is running!!')
})
通过async和await来获取到异步的数据,然后,通过try..Catch..来捕获异常信息
6.添加数据
添加数据步骤
- 1.获取请求体数据
- 获取请求体数据需要提前配置解析表单请求体,
express.json(),可以解析application/json格式的数据,express.urlencoded(),可以解析application/x-www-form-urlencoded格式的数据,否则,通过- 2.验证数据
- 3.验证通过,将数据保存在db中
代码如下:
const express = require('express');
const app = express()
const fs = require('fs')
const { getDb } = require('./db')
const { saveDb } = require('./db')
//配置解析表单请求体: ‘application/json’
app.use(express.json())
//配置解析表单请求体:‘application/x-www-form-urlencoded’
app.use(express.urlencoded())
// 查询任务
app.get('/todos', async (req, res) => {
try {
let db = await getDb();
res.status(200).json(db.todos);
} catch (err) {
res.status(500).json({
error: err.message
})
}
})
// 查询单个任务
app.get('/todos/:id', async (req, res) => {
try {
let db = await getDb();
let todo = db.todos.find(todo => todo.id.toString() === req.params.id);
if (!todo) {
return res.status(404).json({
data: 'not found'
})
}
res.status(200).json(todo)
} catch {
res.status(500).json({
error: err.message
})
}
})
// 添加任务
app.post('/todos', async (req, res) => {
try {
// 1. 获取请求体数据
const todo = req.body;
// 2. 验证数据
if (!todo.name) {
return res.status(422).json({
error: 'The file name is required!!'
})
}
// 3。验证通过,将数据存储到db中
const db = await getDb();
const lastTodo = db.todos[db.todos.length - 1];
todo.id = lastTodo ? lastTodo.id + 1 : 1;
db.todos.push(todo)
await saveDb(db)
res.status(200).json(todo)
} catch (err) {
res.status(500).json({
error: err.message
})
}
})
// 修改任务
app.patch('/todos/:id', (req, res) => {
res.send(`patch /todos/${req.params.id}`)
})
// 删除任务
app.delete('/todos/:id', (req, res) => {
res.send(`delete /todos/${req.params.id}`)
})
app.listen(3000, () => {
console.log('server is running!!')
})
注意:需要先配置解析请求体的方式,然后,验证数据的时候lastTodo不要验证lastId,如果是undefined的话会报错,然后将数据保存到db中
savaDb的代码如下:
const fs = require('fs');
const { promisify } = require('util');
const path = require('path')
const readFile = promisify(fs.readFile)
const writeFile = promisify(fs.writeFile)
const dbPath = path.join(__dirname, './db.json')
exports.getDb = async () => {
let data = await readFile(dbPath, 'utf8')
return JSON.parse(data)
}
exports.saveDb = async (db) => {
const data = JSON.stringify(db, null, ' ')
await writeFile(dbPath, data);
}
注意:传入writeFile的数据需要是字符串格式,传入json格式会报错,JSON.stringify的第三个参数是确保json数据两个空格的缩进
7.修改数据和删除数据
const express = require('express');
const fs = require('fs');
const { getDb } = require('./db');
const { saveDb } = require('./db')
const app = express()
app.use(express.json())
app.use(express.urlencoded())
// 查询所有数据
app.get('/todos', async (req, res) => {
try {
let db = await getDb();
res.status(200).json(db.todos)
} catch (err) {
res.status(500).json({
error: err.message
})
}
})
// 查询单个数据
app.post('/todos/:id', async (req, res) => {
try {
const db = await getDb();
const todo = db.todos.find(todo => todo.id.toString() === req.params.id);
if (!todo) {
return res.status(404).end()
}
res.status(200).json(todo)
} catch (err) {
res.status(500).json({
error: res.message
})
}
})
// 添加数据
app.post('/todos', async (req, res) => {
try {
const todo = req.body;
if (!todo) {
return res.status(422).json({
error: 'The name is required!!'
})
}
const db = await getDb();
const lastTodo = db.todos[db.todos.length - 1];
const lastId = lastTodo ? lastTodo.id + 1 : 1
todo.id = lastId;
db.todos.push(todo)
await saveDb(db)
res.status(200).json(todo)
} catch (err) {
res.status(500).json({
error: err.message
})
}
})
// 修改数据
app.patch('/todos/:id', async (req, res) => {
try {
const data = req.body;
const db = await getDb();
const todo = db.todos.find(todo => todo.id.toString() === req.params.id)
todo.name = data.name;
res.status(200).json(db.todos)
} catch (err) {
res.status(500).json({
error: err.message
})
}
})
// 删除数据
app.delete('/todos/:id', async (req, res) => {
try {
const db = await getDb()
const index = db.todos.findIndex(todo => todo.id.toString() === req.params.id);
if (index == -1) { //判断如果没有查到index的情况
return res.status(404).end()
}
db.todos.splice(index, 1)
await saveDb(db)
res.status(200).json(db)
} catch (err) {
res.status(500).json({
error: err.message
})
}
})
app.listen(3000, () => {
console.log('server is running!!!')
})