Custom Validators

Abolish provides two validator spaces: Global and Standalone

A Global validator is available to all abolish instances, while a standalone validator is available to the instance it was added to.

The standalone space gives you the ability to group and isolate related validators.

Validator Object

const validator = {
    name: 'validatorName',
    error: `Optional validator error.`,
    validator: (value, option, helpers) => boolean  // or `AbolishError` or `void`
};

// Add To Global validators
Abolish.addGlobalValidator(validator);

// Or Add to standalone instance.
const abolish = new Abolish();
abolish.addValidator(validator);
const validator = {
    isAsync: true,
    name: 'validatorName',
    error: `Optional validator error.`,
    validator: async (value, option, helpers) => boolean  // or `AbolishError` or `void`
}

// Add To Global validators
Abolish.addGlobalValidator(validator)

// Or Add to standalone instance.
const abolish = new Abolish();
abolish.addValidator(validator)

Note: The only difference between the Sync and Async validators is the isAsync parameter. Once set to true will be considered as async.

Validator Parameters

  • isAsync: Required and must be set to true for async validators.
  • name: Used to make reference to the validator.
  • validator: The validation function. To fail a validation, this function must throw an error or return false . Anything else is considered a pass.
  • error: Optional error message for the validator. Abolish will override it if an error is thrown in the validator function or if the helper.error() method is called
Note:

The error message can contain two keywords that will be parsed by abolish when found.

  • :param The key of the Object being validated or the name of the variable being validated
  • :option The option passed to the validator in the rules object.

Create a Validator

/**
 * The syntax below creates a validator named `MyValidator`
 * And logs all the arguments it receives during validation.
 */
Abolish.addGlobalValidator({
  name: 'MyValidator',
  validator: (val, opt, helpers) => {
    // log all arguments
    console.log([val, opt, helpers])
    
    // fail by returning false.
    return false;
  },
  error: ':param failed myValidator'
})

Validator Function Arguments

  • 1st - val: The value of the variable being validated.
  • 2nd - opt: The option passed to the validator in the rules object.
  • 3rd - helpers: An object containing the error, modifier & abolish helpers

Let's run some validation to see how MyValidator turns out.

Abolish.attempt('value', 'MyValidator:option');

// will log
['value', 'option', {error, modifier, abolish}]

// And throw
// Error: Variable failed myValidator

Now that you have understood how the validator function works and the arguments it receives, you should be able to use abolish perfectly.

Pass/Fail Validation

Any validation will pass unless:

  • False is returned.
  • Error is thrown.
  • AbolishError is returned.
Abolish.addGlobalValidator({
  name: 'MyValidator',
  validator: (input) => input // return input.
})

Abolish.attempt(0, 'MyValidator'); //  pass
Abolish.attempt(null, 'MyValidator'); //  pass
Abolish.attempt(undefined, 'MyValidator'); // pass
Abolish.attempt(true, 'MyValidator'); // pass
Abolish.attempt(false, 'MyValidator'); // fail
Abolish.addGlobalValidator({
  name: 'MyValidator',
  validator: () => {
    // return nothing
  }
})

Abolish.attempt(null, 'MyValidator'); // void = pass
Abolish.addGlobalValidator({
  name: 'MyValidator',
  validator: (input, opt, {error}) => {
    if (input === 'throw') {
      throw new Error('I was asked to throw an error!');
    } else if (input === 'error') {
      return error('Error returned!') // AbolishError
    }
  }
})

Abolish.attempt(undefined, 'MyValidator'); // pass

Abolish.attempt('throw', 'MyValidator'); // Fail
// Error: I was asked to throw an error!

Abolish.attempt('error', 'MyValidator'); // Fail
// Error: Error returned!

Modifying Data

Abolish provides a helper method for modifying the current data being validated. For example:

Abolish.addGlobalValidator({
  name: 'ValidateEmail',
  validator: (email, opt, {modifier}) => {
    
    // Validate email using regex
    if (!(/^[^\s@]+@[^\s@]+\.[^\s@]+$/).test(email)) {
      throw new Error('Email is invalid!')
    }
    
    // Change value to lowercase.
    modifier.setThis(email.toLowerCase())
  }
})
const email = '[email protected]';
const newEmail = Abolish.attempt(email, 'ValidateEmail');

console.log([email, newEmail]);
// Will log:
["[email protected]", "[email protected]"]
const data = {
  email: "[email protected]",
  password: "password"
};

const [err, validated] = Abolish.validate(data, {
  email: 'required|ValidateEmail',
  password: 'required|min:6'
})

console.log([data, validated]);
// Will log:
[
  {email: "[email protected]", password: "password"}, // original
  {email: "[email protected]", password: "password"} // modified.
]

Types

Reference: All types are defined in abolish/src/Types.d.ts

/**
 * Validator function return type.
 */
type AbolishValidatorFunctionResult = boolean | AbolishError | void;

/**
 * Validator function helper context.
 */
type AbolishValidatorFunctionHelper = {
    error: (message: string, data?: any) => AbolishError;
    modifier: ObjectModifier;
    abolish: Abolish;
};

/**
 * validator function structure.
 */
type AbolishValidatorFunction = (
    value: any,
    option: any,
    helpers: AbolishValidatorFunctionHelper
) => AbolishValidatorFunctionResult | Promise<AbolishValidatorFunctionResult>;

/**
 * Validator structure.
 */
interface AbolishValidator {
    name: string;
    description?: string;
    validator: AbolishValidatorFunction;
    error?: string;
    isAsync?: true;
}

interface AbolishAsyncValidator extends Omit<AbolishValidator, "isAsync"> {
    isAsync: true;
}