Home

Awesome

Iodine

Iodine.js is a micro client-side validation library. It has no dependencies and can be used in isolation or as part of a framework. Iodine also supports chainable rules, allowing you to verify that a piece (or pieces) of data satisfy multiple criteria.

Upgrading

Version 8+ of Iodine involved a major rewrite with numerous breaking changes. It is therefore recommended that existing projects continue to use version 7 (or lower), while version 8 (or higher) should be reserved for newer projects.

Installation

The easiest way to pull Iodine into your project is via a CDN (be sure to update the build number):

<script src="https://cdn.jsdelivr.net/npm/@caneara/iodine@8.5.0/dist/iodine.min.umd.js" defer></script>

You can also pull Iodine into your project via NPM:

npm i @caneara/iodine

Usage

Iodine is automatically added to the window namespace, making it available anywhere. This is the recommended way to use Iodine if your project does not involve compilation or imports. Even if your project does involve compilation, it is often easier to just use the instance added to the window namespace.

Alternatively, if you are comfortable using imports, or you want to create your own instance, then you can import Iodine like so:

import Iodine from '@caneara/iodine';

const instance = new Iodine();

Basic Validation

Iodine includes a bunch of validation rules that you can access via their associated methods. This makes it quick and easy to check if an item is, for example, an integer or a date.

Iodine's rules are prefixed with assert. So, to check if an item is an integer, you'd use the following code:

let item_1 = 7;
let item_2 = 'string';

Iodine.assertInteger(item_1); // true
Iodine.assertInteger(item_2); // false

See below for a complete list of Iodine's included validation rules.

Advanced Validation

While checking if an item conforms to an individual validation rule can be useful, you'll often want to check if an item conforms to multiple rules. For example, an email address may be required, must be a string, and must satisfy an email address regular expression.

To address these needs, Iodine offers 'single item checks' and 'multiple item checks'...

Single Item Checks

This approach is preferred if you have one item that you need to test against multiple rules (like the email address example described above). To perform a 'single item check', call the main assert method. The method takes two parameters. The first, is the item to check. The second, is an array of validation rules that should be run in sequence e.g.

let item_1 = 7;
let item_2 = 'string';

Iodine.assert(item_1, ['required', 'integer']);
Iodine.assert(item_2, ['required', 'integer']);

As you can see in the example, the validation rules are expressed using strings. To find the string representation for a validation rule, review the existing list.

Unlike individual assertions (which return a boolean), the assert method returns an object containing a report. When the item passes all of the rules, you'll get this:

{
    valid : true,
    rule  : '',
    error : '',
};

If the item fails to validate, the report will contain the first rule that it failed to satisfy, along with the associated error message:

{
    valid : false,
    rule  : 'integer',
    error : 'Value must be an integer',
};

Multiple Item Checks

This approach is preferred when you need to check multiple items against a bunch of different validation rules e.g. when submitting a form containing several fields.

As with 'single item checks', you should call the assert method, however for both parameters, you will need to supply an object. The first object should contain the items to be validated, while the second should consist of the rules for each item e.g.


const items = {
    name     : 5,
    email    : 'test@example.com',
    password : 'abcdefgh',
};

const rules = {
    name     : ['required', 'string'],
    email    : ['required', 'email'],
    password : ['required'],
};

Iodine.assert(items, rules);

Unlike 'single item checks', the report is slightly different. It contains a top level valid key that allows you to easily check if everything passed or something failed. It then contains a fields key, which contains sub-reports for each item. The sub-report is the same thing you'd get for a 'single item check'. Here's the report for the code example shown above:

{
    valid  : false,
    fields : {
        name : {
            valid : false,
            rule  : 'string',
            error : 'Value must be a string',
        },
        email : {
            valid : true,
            rule  : '',
            error : '',
        },
        password : {
            valid : true,
            rule  : '',
            error : '',
        }
    },
};

Additional parameters

Some rules require extra parameters e.g.

let item_1 = 7;
let item_2 = 4;

Iodine.assertMin(item_1, 5); // true
Iodine.assertMin(item_2, 5); // false

For advanced validation, you can supply the parameters by appending them to the rule with a semicolon separator e.g.

let item_1 = 7;
let item_2 = 4;

Iodine.assert(item_1, ['required', 'integer', 'min:5']);
Iodine.assert(item_2, ['required', 'integer', 'min:5']);

Or, if you prefer, you can supply the rule as an object instead of a string separated by a semicolon:

Iodine.assert(8, ['required', 'integer', { rule : 'min', param : 7 }, 'max:10']);

Optional values

For advanced validation, you may wish to allow for optional values. Iodine supports this with the optional rule:

let item_1 = 7;
let item_2 = null;
let item_3 = 'string';

Iodine.assert(item_1, ['optional', 'integer']);
Iodine.assert(item_2, ['optional', 'integer']);
Iodine.assert(item_3, ['optional', 'integer']);

IMPORTANT: If you wish to allow for optional values, then it must be the first rule in the array.

Custom Errors

Iodine includes a default set of error messages for the English language. However, you can easily replace them via the setErrorMessages method. This method requires a single parameter, which is an object containing the messages. See Iodine's constructor for an example.

Iodine will automatically replace the [FIELD] and [PARAM] placeholders when an error occurs. As such, you should insert these placeholders at the appropriate position in your new error message e.g.

Iodine.setErrorMessages({ same : `[FIELD] must be '[PARAM]'` });   // English
Iodine.setErrorMessages({ same : `[FIELD] doit ĂȘtre '[PARAM]'` }); // French

Single Errors

In many cases, you won't need to replace all of the error messages. You'll instead want to update one or add a new one. To do that, you should instead call setErrorMessage e.g.

Iodine.setErrorMessage('passwordConfirmation', 'Does not match password');

Custom Errors by Field

Sometimes, it may be necessary to define a specific error message for a field, or you need a label for a field that is different from the name of the variable used.

To achieve this, pass an object to the assert method containing the rule as property and the custom error message as a value e.g.

Iodine.assert(value, ['required'], { 'required' : 'The "Label" must be present.' });

You can also use the same approach for multiple fields e.g.

let items = {
    name : '',
};

let rules = {
    name : ['required']
};

let errors = {
    name : {
        required : 'The "Label" must be present.'
    }
};

Iodine.assert(items, rules, errors);

Default field name

Since 'single item checks' don't support field names, Iodine uses the default instead (which is 'Value'). If 'Value' is not suitable, then you can call the setDefaultFieldName method and supply an alternative string value to use instead e.g.

Iodine.setDefaultFieldName('Valeur');

Note that you must call setDefaultFieldName before calling assert.

Available rules

The following validation rules are available:

RuleString KeyDescription
assertAfter(date/integer)'after'Verify that the item is a Date after a given Date or timestamp
assertAfterOrEqual(date/integer)'afterOrEqual'Verify that the item is a Date after or equal to a given Date or timestamp
assertArray'array'Verify that the item is an array
assertBefore(date/integer)'before'Verify that the item is a Date before a given Date or timestamp
assertBeforeOrEqual(date/integer)'beforeOrEqual'Verify that the item is a Date before or equal to a given Date or timestamp
assertBoolean'boolean'Verify that the item is either true or false
assertDate'date'Verify that the item is a Date object
assertDifferent(value)'different'Verify that the item is different to the supplied value (uses loose compare)
assertEnds(value)'ends'Verify that the item ends with the given value
assertEmail'email'Verify that the item is a valid email address
assertFalsy'falsy'Verify that the item is either false, 'false', 0 or '0'
assertIn(array)'in'Verify that the item is within the given array
assertInteger'integer'Verify that the item is an integer
assertJson'json'Verify that the item is a parsable JSON object string
assertMaxLength(limit)'maxLength'Verify that the item's character length does not exceed the given limit
assertMinLength(limit)'minLength'Verify that the item's character length is not under the given limit
assertMax(limit)'max'Verify that the item's numerical value does not exceed the given limit
assertMin(limit)'min'Verify that the item's numerical value is not under the given limit
assertNotIn(array)'notIn'Verify that the item is not within the given array
assertNumeric'numeric'Verify that the item is number or a numeric string
assertOptional'optional'Allow for optional values (only for use with multiple checks)
assertRegexMatch(exp)'regexMatch'Verify that the item satisfies the given regular expression
assertRequired'required'Verify that the item is not null, undefined or an empty string
assertSame(value)'same'Verify that the item is the same as the supplied value (uses loose compare)
assertStartsWith(value)'startsWith'Verify that the item starts with the given value
assertString'string'Verify that the item is a string
assertTruthy'truthy'Verify that the item is either true, 'true', 1 or '1'
assertUrl'url'Verify that the item is a valid URL
assertUuid'uuid'Verify that the item is a UUID

Examine the tests for examples of how to use each rule.

Custom rules

Iodine allows you to add your own custom validation rules through the rule method. This method accepts two parameters. The first, is the name of the rule. The second, is the closure that Iodine should execute when calling the rule e.g.

Iodine.rule('lowerCase', (value) => value === value.toLowerCase());

IMPORTANT: Iodine will automatically make the first letter of the rule's name uppercase and prefix it with 'assert'. You should therefore avoid adding the prefix yourself e.g.

Iodine.rule('lowerCase');       // right
Iodine.rule('assertLowerCase'); // wrong

If your rule needs to accept a parameter, simply include it in your closure as the second argument e.g.

Iodine.rule('equals', (value, param) => value == param);

You can also add error messages for your custom rules e.g.

Iodine.rule('equals', (value, param) => value == param);
Iodine.setErrorMessage('equals', "[FIELD] must be equal to '[PARAM]'");

Asynchronous rules

Previous versions of Iodine supported asynchronous custom rules using async / await. This has since been removed to make the library easier to maintain. If you were using asynchronous rules, then the preferred strategy is to execute your asynchronous logic first, store the result, and then have Iodine validate it.

Contributing

Thank you for considering a contribution to Iodine. You are welcome to submit a PR containing additional rules, however to be accepted, they must explain what they do, be useful to others, and include a suitable test to confirm they work correctly.

After pulling the project, to install the dependencies:

npm install

To run the tests

npm run test

License

The MIT License (MIT). Please see License File for more information.