[Resolved] Error: Cannot find module 'Validator' ( How to create a custom validation and sanitization )


#1

I’m trying to create new custom validation rule.
I’ve created new file start/hooks.js and put the code below inside it.

const Validator = use('Validator')
const Database = use('Database')

const existsFn = async (data, field, message, args, get) => {
  const value = get(data, field)
  if (!value) {
    /**
     * skip validation if value is not defined. `required` rule
     * should take care of it.
    */
    return
  }

  const [table, column] = args
  const row = await Database.table(table).where(column, value).first()

  if (!row) {
    throw message
  }
}

Validator.extend('exists', existsFn)

The console shows me an error: Cannot find module 'Validator'.

Where am I wrong? This code is from https://adonisjs.com/docs/4.1/validator#_extending_validator

  • My package.json has "@adonisjs/validator": "^5.0.6",

  • I’ve installed validator

  • I can use validators from controllers but when I put this code in hooks.js, my api broke.


#3

After much research, I found a solution to create custom validation rules.

How to create custom validation, step by step:

1. Install Validator Provider

adonis install @adoniscli/validator

2. Register Validator Provider

At app/start/app.js, in providers array, add:

  '@adonisjs/validator/providers/ValidatorProvider',

3. Create a Provider

adonis make:provider CustomValidation

This command will create a file named CustomValidationProvider.js in the providers/ directory.

4. File Created

The file content is:

'use strict'

const { ServiceProvider } = require('@adonisjs/fold')

class CustomValidationProvider extends ServiceProvider {
  /**
   * Register namespaces to the IoC container
   *
   * @method register
   *
   * @return {void}
   */
  register () {
    //
  }

  /**
   * Attach context getter when all providers have
   * been registered
   *
   * @method boot
   *
   * @return {void}
   */
  boot () {
    //
  }
}

module.exports = CustomValidationProvider

5. Write your own functions

   * Validate if a person exists
   *
   * @usage personExists
   */
  async _personExists(data, field, message, args, get) {
    // Same as data[ field ]. 
    const personId = get(data, field);
    // Get info from DB
    const row = await use('App/Models/Person').find(personId);
    // If this person doesn't exists 
    if (!row) {
      throw 'Person not found';
    }
  }

You can write as many functions as you want.

6. Register your function as validation

Inside boot()

  boot() {
    // require Validator
    const Validator = use('Validator');
    // Register
    Validator.extend('personExists', this._personExists, 'Pessoa inexistente');
  }

7. Register your new validation

At start/app.js, insert your new provider at the end of providers array

  path.join(__dirname, '..', 'providers', 'CustomValidationProvider')

8. Done

Now you can use your new validation without problems.

{ 
  people_id: 'required|integer|unique:users,people_id|personExists',
}

9. Bonus

You can create a sanitization of variables within the same file of the provider, simply include the functions normally and register them inside boot().

  boot() {
    const Validator = use('Validator');

    Validator.extend('personExists', this._personExists, 'not found person');

    // Sanitization
    Validator.sanitizor.toLower = value => String(value).toLowerCase();
    Validator.sanitizor.toUpper = value => String(value).toUpperCase();
  }