moleculer icon indicating copy to clipboard operation
moleculer copied to clipboard

Error: Invalid 'undefined' type in validator schema.

Open juandl opened this issue 3 years ago • 2 comments

Prerequisites

Please answer the following questions for yourself before submitting an issue.

  • [x ] I am running the latest version
  • [ x] I checked the documentation and found no answer
  • [x ] I checked to make sure that this issue has not already been filed
  • [x ] I'm reporting the issue to the correct repository

Current Behavior

Running moleculer in "development mode" using a custom validator "Joi" after saving the file "package.json" (without any changes), Runner detect a "change", a soon moleculer start it will throw an error.

**[Runner] Invalid 'undefined' type in validator schema. Error: Invalid 'undefined' type in validator schema.**

Here is the custom validator using Joi

const BaseValidator = require('moleculer').Validators.Base;
const { ValidationError } = require('moleculer').Errors;

const _ = require('lodash');

class JoiValidator extends BaseValidator {
  constructor() {
    super();
    
    this.Joi = require('joi');
  }

  compile(schema) {
    //Check if schema is joi format
    if (this.Joi.isSchema(schema)) {
      return (params) => this.validate(params, schema);
    } else if (this.validator) {
      //Use fastest-validator
      return this.validator.compile(_.cloneDeep(schema));
    }
  }

  /**
   * Clean messages
   * From "\"name\" is required"
   * to "name is required"
   * @param {string} msg
   * @returns {string}
   */
  cleanMessage(msg) {
    if (!msg) return '';

    return _.replace(msg, /([^\w\d\s])+/g, '');
  }

  /**
   * Validate joi schema
   * @param {Object} params
   * @param {*} schema
   * @returns
   */
  validate(params, schema) {
    let errors = [];

    if (!this.Joi.isSchema(schema) && _.isFunction(schema)) {
      throw new ValidationError('Not Joi Schema', null, {
        message: 'No Schema Joi',
      });
    }

    // Check if is merged schema
    if (_.get(params, 'body', null)) {
      params = params.body;
    }

    //Validate schema
    const { error } = schema.validate(params, {
      abortEarly: true,
    });

    if (!_.isEmpty(error)) {
      /**
       * Create Custom Error
       */
      if (error.details) {
        _.forEach(error.details, (value) => {
          let errorObj = {
            type: null,
            field: null,
            uid: null,
            message: null,
          };

          //Assign type
          if (value.type) {
            errorObj.type = value.type;
          }

          //Assign field name
          if (value.context) {
            errorObj.field = value.context.key;
          }

          //Assign message error
          if (value.message) {
            errorObj.message = this.cleanMessage(value.message);
          }

          //Create uid
          if (errorObj.type && errorObj.field) {
            errorObj.uid = `${errorObj.field}.${errorObj.type}`;
          }

          errors.push(errorObj);
        });
      }

      /**
       * Return errors
       */
      if (error) {
        throw new ValidationError(
          this.cleanMessage(error.message),
          null,
          errors
        );
      }
    }

    return true;
  }
}

module.exports = JoiValidator;

Steps to Reproduce

Please provide detailed steps for reproducing the issue.

  1. Create a custom validator (using the above code)
  2. Create an example service and add validations using Joi Scheme
Joi.object({
     name: Joi.string().required(),
})
  1. Run Moleculer (should run well)
  2. Open "package.json" and don't do anything just save the file, after that runner will throw an error

Context

Please provide any relevant information about your setup. This is important in case the issue is not reproducible except for under certain conditions.

  • Moleculer version: 0.14.23
  • NodeJS version: 16 LTS
  • Operating System: Windows 11 /Ubuntu 20.4 LTS

juandl avatar Sep 18 '22 21:09 juandl

I believe this happens because on https://github.com/moleculerjs/moleculer/blob/master/src/validators/index.js#L32 this function is trying to look for a match on the object "Validators" but it doesn't exist so it runs a default as "Fastest" and when it reaches "Fastest" compile function, it won't work as Joi schema is an object with functions, (no valid schema for Fastest)

So I'm not sure if the middleware (resolve function) should search for the "custom" validator on the moleculer.config.js

juandl avatar Sep 18 '22 21:09 juandl

I try to create a small solution that is updating this function resolve

like this

function resolve(opt) {
	if (opt instanceof Validators.Base) {
		return opt;
	} else if (isString(opt)) {
		let ValidatorClass = getByName(opt);
		if (ValidatorClass) return new ValidatorClass();

		throw new BrokerOptionsError(`Invalid Validator type '${opt}'.`, { type: opt });
	//If is a customer validator <======= this part
	} else if(opt.constructor && opt.constructor.name) { 
		return opt;
	} else if (isObject(opt)) {
		let ValidatorClass = getByName(opt.type || "Fastest");
		if (ValidatorClass) return new ValidatorClass(opt.options);
		
		throw new BrokerOptionsError(`Invalid Validator type '${opt.type}'.`, {
				type: opt.type
		});
	} 

	return new Validators.Fastest();
}

checking if the custom validator is a "class" looking for a constructor and the name, going this way, there's not an error at all, if no custom validator is found, it will continue to detect if is an "object" and check for the "type" or return a default validator "fastest"

juandl avatar Sep 18 '22 22:09 juandl

Thanks the report, I've fixed it. Next version will be released.

icebob avatar Oct 01 '22 17:10 icebob