Another joi validation middleware for restify. Inspired by restify-joi-validator
npm i restify-joi-middleware --save
Requires Node >8.0.0
.
This example is available here as well.
const Joi = require('joi')
const restify = require('restify')
const {name, version} = require('./package.json')
const validator = require('restify-joi-middleware')
const server = restify.createServer({name, version})
server.use(restify.plugins.acceptParser(server.acceptable))
server.use(restify.plugins.queryParser())
server.use(restify.plugins.bodyParser({mapParams: false}))
server.use(restify.plugins.gzipResponse())
server.use(validator()) // see "Middleware Options" for all options
// additional middleware etc
server.get({
path: '/:id',
validation: {
schema: {
params: Joi.object().keys({
id: Joi.number().min(0).required()
}).required()
}
}
}, (req, res, next) => {
res.send(200, {id: req.params.id})
next()
})
server.post({
path: '/',
validation: {
schema: {
body: Joi.object().keys({
name: Joi.string().required()
}).required()
},
// overrides middleware settings for this route
options: {
joiOptions: {
allowUnknown: false
}
}
}
}, (req, res, next) => {
res.send(201, {id: 1, name: req.body.name})
next()
})
server.put({
path: '/:id',
// Joi.object().keys({}) schemas work too
validation: {
schema: Joi.object().keys({
params: Joi.object().keys({
id: Joi.number().min(0).required()
}).required(),
body: Joi.object().keys({
id: Joi.number().min(0).required(),
name: Joi.string().required()
}).required()
}).assert('params.id', Joi.ref('body.id'))
}
}, (req, res, next) => {
res.send(200, {id: 1, name: req.body.name})
next()
})
server.listen(8080, () => console.log(`${server.name} listening on: ${server.url}`))
Given the server above:
curl 'http://localhost:8080/'
# result
# {
# "code": "BadRequest",
# "message": "child \"params\" fails because [child \"id\" fails because [\"id\" must be a number]]"
# }
curl -X POST -H "Content-Type: application/json" -d '{"color":"Blue"}' http://127.00.1:8080/
# result
# {
# "code":"BadRequest",
# "message":"child \"body\" fails because [child \"name\" fails because [\"name\" is required]]"
# }
curl -X PUT -H "Content-Type: application/json" -d '{"id": 1, "name":"Max"}' http://127.00.1:8080/2
# result
# {
# "code":"BadRequest",
# "message":"\"params.id\" validation failed because \"params.id\" failed to pass the assertion test"
# }
If you don't like how errors are returned or transformed from Joi errors to restify errors, you can change that for the entire plug-in. For example:
server.use(validator({
joiOptions: {
convert: true,
allowUnknown: true,
abortEarly: false
// .. all additional joi options
},
// changes the request keys validated
keysToValidate: ['params', 'body', 'query', 'user', 'headers', 'trailers', 'files'],
// changes how joi errors are transformed to be returned - no error details are returned
// in this case
errorTransformer: (validationInput, joiError) => new restifyErrors.BadRequestError(),
// changes how errors are returned
errorResponder: (transformedErr, req, res, next) => {
res.send(400, transformedErr)
return next()
}
}))
You can also override any middleware setting above per route, e.g.:
server.get({
path: '/:id',
validation: {
schema: {
params: Joi.object().keys({
id: Joi.number().min(0).required()
}).required()
},
options: {
joiOptions: {
allowUnknown: false
// .. all additional joi options
},
// changes how errors are returned
errorResponder: (transformedErr, req, res, next) => {
res.send(400, transformedErr)
return next()
},
// changes how joi errors are transformed to be returned - no error details are returned
// in this case
errorTransformer: (validationInput, joiError) => new restifyErrors.BadRequestError()
// keysToValidate can also be overridden here
}
}
}, (req, res, next) => {
res.send(200, {id: req.params.id})
next()
})
npm test