这样的库非常棒,但如果我们能以更无缝的方式使用它们,比如在请求管道中使用,那不是更好吗?首先让我们看看如何在Node.js的Express应用程序中使用Joi:
const Joi = require('joi');
app.post('/blog', async (req, res, next) => {
const { body } = req; const
blogSchema = Joi.object().keys({
title: Joi.string().required
description: Joi.string().required(),
authorId: Joi.number().required()
});
const result = Joi.validate(body, blogShema);
const { value, error } = result;
const valid = error == null;
if (!valid) {
res.status(422).json({
message: 'Invalid request',
data: body
})
} else {
const createdPost = await api.createPost(data);
res.json({ message: 'Resource created', data: createdPost })
}
});
以上方法可行。但是我们需要为每个路由执行以下操作:
- 创建模式
- 调用 validate()
这种方法有点不够优雅。我们想要一些看起来更加流畅的东西。
构建中间件
让我们尝试将其重构为一个中间件。在 Express 中,中间件只是我们需要时可以插入请求管道的东西。在我们的情况下,我们希望尝试验证我们的请求并尽早确定是否值得继续进行或中止它。
所以让我们看看中间件。它只是一个函数,对吧:
const handler = (req, res, next) = {
const middleware = (req, res, next) => {
app.post( '/blog', middleware, handler )
如果我们能够向中间件提供模式,那将会很方便,因为在中间件函数中我们只需要做类似于这样的事情:
(req, res, next) => {
const result = Joi.validate(schema, data)
}
我们可以创建一个带有工厂函数和模块的模块,用于管理所有的模式。让我们先来看看我们的工厂函数模块:
const Joi = require('joi');
const middleware = (schema, property) => {
return (req, res, next) => {
const { error } = Joi.validate(req.body, schema);
const valid = error == null;
if (valid) {
next();
} else {
const { details } = error;
const message = details.map(i => i.message).join(',');
console.log("error", message);
res.status(422).json({ error: message }) }
}
}
module.exports = middleware;
接下来,让我们为所有模式创建一个模块,就像这样:
// schemas.js
const Joi = require('joi')
const schemas = {
blogPOST: Joi.object().keys({
title: Joi.string().required
description: Joi.string().required()
})
// define all the other schemas below
};
module.exports = schemas;
好的,那么让我们回到我们的应用程序文件:
const express = require('express')
const cors = require('cors');
const app = express()
const port = 3000
const schemas = require('./schemas');
const middleware = require('./middleware');
var bodyParser = require("body-parser");
app.use(cors());
app.use(bodyParser.json());
app.get('/', (req, res) => res.send('Hello World!'))
app.post('/blog', middleware(schemas.blogPOST) , (req, res) => {
console.log('/update');
res.json(req.body);
});
app.listen(port, () => console.log(`Example app listening on port ${port}!`))
Joi.validate
自版本16起已被弃用。为了保持相同的解决方案,现在您只需使用services.validate([], callback)
或services.validateAsync([])
来替代Joi.validate([], services)
。 - Jeffery ThaGintokiservice = []
的验证,使用Joi.array().min(1).items(service)
确保service包含一些值。 - sujeet