I want to validate my Express routes before calling the controller logic. I use joi and created a validator which is able to validate the Request object against the schema object
import { Request, Response, NextFunction } from 'express';
import joi, { SchemaLike, ValidationError, ValidationResult } from '@hapi/joi';
import { injectable } from 'inversify';
@injectable()
export abstract class RequestValidator {
protected validateRequest = (validationSchema: SchemaLike, request: Request, response: Response, next: NextFunction): void => {
const validationResult: ValidationResult<Request> = joi.validate(request, validationSchema, {
abortEarly: false
});
const { error }: { error: ValidationError } = validationResult;
if (error) {
response.status(400).json({
message: 'The request validation failed.',
details: error.details
});
} else {
next();
}
}
}
Next I created a deriving class which creates the validationSchema and calls the validateRequest
method. For the sake of simplicity I will show the "deleteUserById" validation
import { Request, Response, NextFunction } from 'express';
import joi, { SchemaLike } from '@hapi/joi';
import { injectable } from 'inversify';
import { RequestValidator } from './RequestValidator';
@injectable()
export class UserRequestValidator extends RequestValidator {
public deleteUserByIdValidation = async (request: Request, response: Response, next: NextFunction): Promise<void> => {
const validationSchema: SchemaLike = joi.object().keys({
params: joi.object().keys({
id: joi.number().required(),
})
});
this.validateRequest(validationSchema, request, response, next);
}
}
Important note: I create the SchemaLike
that way because some routes might have params, body, query
which need to get validated in one run.
When calling the Route
DELETE /users/1
the validation always fails. I get this error
UnhandledPromiseRejectionWarning: TypeError: joi_1.default.validate is not a function
The error occurs with every validation, whether called correctly or not. Does someone know how to fix it?
您可以通过将joi.validate(request, validationSchema
更改为validationSchema.validate(request
As joi.validate()
在 v16 中不再支持来修复它。它在 API 文档和发行说明中有明确记录。
Update version of joi doesn't work with Joi.validate(req.body,schema);
No need to use the object separately. Use this as following. It Worked for me smoothly. Do let me know if I am wrong at anything:
const Joi = require('@hapi/joi');
const schema = Joi.object({
name:Joi.string().min(3).required(),
email:Joi.string().min(4).required().email(),
password:Joi.string().min(6).required()
});
router.post('/register', async (req,res) => {
//updated joi
// This is a shorter version
const { error } = schema.validate(req.body);
// Error in response
res.send(error.details[0].message);
// WORKING WITH DEPRECATED VERSION
// const Validation = Joi.validate(req.body,schema);
// res.send(Validation);
Hit the same problem when using express-joi-validation
.
If it's ok for you to use version 15, downgrade Joi will make it.
npm uninstall --save @hapi/joi
npm install --save @hapi/joi@15.0.3
I experienced joi.validate()
is not a function also. I checked their documentation and got a fix for it.
const Joi = require('@hapi/joi');
const schema = Joi.object({
name:Joi.string().min(6).required(),
email:Joi.string().min(6).required().email(),
password:Joi.string().min(6).required()
});
router.post('/register', (req, res) => {
// VALIDATE BEFORE SAVING A USER
const Validation = schema.validate(req.body);
res.send(Validation);
})
This works as expected and gives no further error.
You can fix it by changing Joi.validate(request, validationSchema)
to validationSchema.validate(request)
As Joi.validate()
is no longer supported in v16.
For new version
const schema = Joi.object({ name: Joi.string() .min(6) .required(),
email: Joi.string() .min(6) .required() .email(),
password: Joi.string() .min(6) .required() });
const validation = schema.validate(req.body);
Instead of downgrading the Joi
version it's better to quickly have a look at API of the newest version and check the correct way of using it.
Here is the link to the latest Joi API at the moment (16.1.7), where you can see an example of using validate
.
Also to make sure you know what has been changed in next version of a lib that you use, it is good to have a look at the Release notes, here is a link to a Joi version 16 Release notes where you can see all the changes/new features, and FYI you can see info about validate
method:
Remove Joi.validate() and Joi.describe() (call direct on schema instead) (#1941)
For the new version
const schema = Joi.object({ name: Joi.string() .min(6) .required(),
email: Joi.string() .min(6) .required() .email(),
password: Joi.string() .min(6) .required() });
const validation = schema.validate(req.body);
res.send(validation);
Here are some fixed with snippet codes :)
Install below npm package.
npm install --save @hapi/joi@15.0.3
req-validator.js file
const Joi = require("@hapi/joi");
const registerValidation = data => {
const schema = {
name : Joi.string().min(4).required(),
email: Joi.string().min(4).required().email(),
password: Joi.string().min(4).required()
};
return Joi.validate(data,schema);
}
module.exports.registerValidation = registerValidation;
finally, calling the validation method in the controller.
const router = require("express").Router();
const {registerValidation} = require("./req-validator")
router.post("/register",async(req,res)=> {
const {error} = registerValidation(req.body);
if(error){
return res.status(400).send(error.details[0].message);
}
// logic to save in DB....
}
Simply You can check whether you have @hapi/joi installed and required in your file
and for validation use This approach.
const schema= Joi.object().keys({ name: Joi.string().min(6).required(), email: Joi.string().min(6).email(), password: Joi.string().min(6).required() }); const validation = schema.validate(req.body); if(validation.error){ res.status(400).send(validation.error.details[0].message); return ; }
I think This is gonna work
Following works with the latest version ("@hapi/joi": "^17.1.1"):
const Joi = require("@hapi/joi");
const schema = Joi.object({
name: Joi.string().min(6).required(),
email: Joi.string().min(6).required().email(),
password: Joi.string().min(6).required(),
});
router.post("/register", async (req, res) => {
const { error } = schema.validate(req.body);
if (error) {
res.json({ ErrorMessage: error.details[0].message });
} else {
res.json({ message: "valid data" });
}
});
Create your validate function like this
const validateUser = function (user) {
const schema = Joi.object({
username: Joi.string().min(5).max(50),
email: Joi.string().required().email().min(5).max(255),
password: Joi.string().required().min(5).max(1024),
});
return schema.validate(user);
};
You will get the error by
const { error } = validateUser({ email: 'admin' });
And the error message by
const message = error.details[0].message;
// Get the instance on schema defination
function validate(model, object, scope) {
const schema = getSchema(model, scope);
return schema.validate(object);
}
// actual middleware factory to validate
module.exports = function ValidationMiddleware(model, scope) {
return (req, res, next) => {
const validationResult = validate(model, req.body, scope);
if (validationResult.error) {
throw new Error(validationResult.error.details[0].message);
} else {
next();
}
};
};
use this
const schema = Joi.object({
name: Joi.string().min(6).required(),
email: Joi.string().min(6).email(),
password: Joi.string().min(6).required()
})
insted of const schema = {...}
and Validate through this:
const validate = schema.validate(req.body)
instead of Joi.validate(req.body,schema)
Here is something straight out of a project I'm working on, using Joi 17.3.0:
PDFCreatorController.exportAsPDF = (req, res) => {
const data = req.body
const schema = Joi.object().keys({
svgDataToExport: Joi.string().required()
})
const isValidPromise = new Promise((resolve) => {
const validation = schema.validate(req.body)
if (validation.error) {
res.status(422).json({
status: 'error',
message: error,
data: data
})
} else {
resolve(data)
}
})
isValidPromise.then(inputDataFromUser => {
try {
const exportAsPDF = PDFCreatorModel.exportAsPDF(inputDataFromUser)
exportAsPDF.then(data => {
res.json(data)
})
} catch (error) {
console.error(error)
return res.status(500).json(error)
}
})
}
Due to Updated version of JOI Package we are all facing this error but here is the solution of that. In Node.js when we facing this error we can solve it applying below solution.
// Example : Here we try to validate user's data
// User's POST Api
const schema = Joi.object({
name: Joi.string().min(1).required(),
email: Joi.string().required().email(),
password: Joi.string().min(8).max(12).required(),
isEmailVerified: Joi.boolean().required(),
forgotPasswordToken: Joi.string().required(),
isDeleted: Joi.boolean().required()
});
try {
const value = await schema.validateAsync(req.body);
}
catch (err) {
return res.status(400).send(err);
}
Lower down the version of joi. to 13.0.1 it will work. in terminal npm i joi@13.0.1. 2.after install check. dependencies in package. Json file.
npm i joi
joi v17.4.x resource: https://joi.dev/api/?v=17.4.2
const schema = Joi.object({
email: Joi.string().email().required(),
password: Joi.string().required().min(5),
});
const result = schema.validate(YourRequest.body);
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.