简体   繁体   中英

joi_1.default.validate is not a function

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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM