Introduction

joi lets you describe your data using a simple, intuitive, and readable language. Like the rest of the hapi ecosystem it fits in, joi allows you to describe your data for both input and output validation, as part of a hapi HTTP server or standalone.

Example

const Joi = require('@hapi/joi');

const schema = Joi.object({
    username: Joi.string()
        .alphanum()
        .min(3)
        .max(30)
        .required(),

    password: Joi.string()
        .pattern(/^[a-zA-Z0-9]{3,30}$/),

    repeat_password: Joi.ref('password'),

    access_token: [
        Joi.string(),
        Joi.number()
    ],

    birth_year: Joi.number()
        .integer()
        .min(1900)
        .max(2013),

    email: Joi.string()
        .email({ minDomainSegments: 2, tlds: { allow: ['com', 'net'] } })
})
    .with('username', 'birth_year')
    .xor('password', 'access_token')
    .with('password', 'repeat_password');


schema.validate({ username: 'abc', birth_year: 1994 });
// -> { value: { username: 'abc', birth_year: 1994 } }

schema.validate({});
// -> { value: {}, error: '"username" is required' }

// Also -

try {
    const value = await schema.validateAsync({ username: 'abc', birth_year: 1994 });
}
catch (err) { }

The above schema defines the following constraints:

General Usage

Usage is a two steps process:

First, a schema is constructed using the provided types and constraints:

const schema = Joi.object({
    a: Joi.string()
});

Note that joi schema objects are immutable which means every additional rule added (e.g.
.min(5)) will return a new schema object.

Second, the value is validated against the defined schema:

const { error, value } = schema.validate({ a: 'a string' });

If the input is valid, then the error will be undefined. If the input is invalid, error is assigned
a ValidationError object
providing more information.

The schema can be a plain JavaScript object where every key is assigned a joi type, or it can be a joi type directly:

const schema = Joi.string().min(10);

If the schema is a joi type, the schema.validate(value) can be called directly on the type. When passing a non-type schema object,
the module converts it internally to an object() type equivalent to:

const schema = Joi.object().keys({
    a: Joi.string()
});

When validating a schema:

assert(value, schema, [message], [options])

Validates a value against a schema and throws if validation fails where:

Joi.assert('x', Joi.number());

attempt(value, schema, [message], [options])

Validates a value against a schema, returns valid object, and throws if validation fails where:

Joi.attempt('x', Joi.number()); // throws error
const result = Joi.attempt('4', Joi.number()); // result -> 4

cache.provision([options])

Provisions a simple LRU cache for caching simple inputs (undefined, null, strings, numbers, and
booleans) where:

checkPreferences(prefs)

Checks if the provided preferences are valid where:

Throws an exception if the prefs object is invalid.

The method is provided to perform inputs validation for the any.validate(])
and any.validateAsync() methods. Validation is not performed
automatically for performance reasons. Instead, manually validate the preferences passed once and
reuse.

compile(schema, [options])

Converts literal schema definition to joi schema object (or returns the same back if already a
joi schema object) where:

const definition = ['key', 5, { a: true, b: [/^a/, 'boom'] }];
const schema = Joi.compile(definition);

// Same as:

const schema = Joi.alternatives().try(
    Joi.string().valid('key'),
    Joi.number().valid(5),
    Joi.object({
        a: Joi.boolean().valid(true),
        b: Joi.alternatives().try(
            Joi.string().pattern(/^a/),
            Joi.string().valid('boom')
        )
    })
);

defaults(modifier)

Creates a new joi instance that applies the provided modifier function to every new schemas
where:

const custom = Joi.defaults((schema) => {

    switch (schema.type) {
        case 'string':
            return schema.allow('');
        case 'object':
            return schema.min(1);
        default:
            return schema;
    }
});

const schema = custom.object();   // Returns Joi.object().min(1)

expression(template, [options]) - aliases: x

Generates a dynamic expression using a template string where:

Template syntax

The template syntax uses {} and {{}} enclosed formulas to reference values as well as perform
number and string operations. Single braces {} leave the formula result as-is, while double
braces {{}} HTML-escape the formula result (unless the template is used for error messages
and the errors.escapeHtml preference flag is set to false).

The formula uses a simple mathematical syntax such as a + b * 2 where the named formula variables
are references. Most references can be used as-is but some can create ambiguity with the formula
syntax and must be enclosed in [] braces (e.g. [.]).

The formulas can only operate on null, booleans, numbers, and strings. If any operation involves
a string, all other numbers will be casted to strings (as the internal implementation uses simple
JavaScript operators). The supported operators are: ^, *, /, %, +, -, <, <=, >,
>=, ==, !=, &&, ||, and ?? (in this order of precedence).

The reference names can have one of the following prefixes:

The formula syntax also supports built-in functions:

And the following constants:

extend(...extensions)

Creates a new customized instance of the joi module where:

Note that the original joi module is not modified by this.

isExpression(expression)

Checks whether or not the provided argument is an expression.

const expression = Joi.x('{a}');
Joi.isExpression(expression); // returns true

in(ref, [options])

Creates a reference that when resolved, is used as an array of values to match against the rule, where:

Can only be used in rules that support in-references.

const schema = Joi.object({
    a: Joi.array().items(Joi.number()),
    b: Joi.number().valid(Joi.in('a'))
});

isRef(ref)

Checks whether or not the provided argument is a reference. Useful if you want to post-process error messages.

const ref = Joi.ref('a');
Joi.isRef(ref); // returns true

isSchema(schema, [options])

Checks whether or not the provided argument is a joi schema where:

const schema = Joi.any();
Joi.isSchema(schema); // returns true

override

A special value used with any.allow(), any.invalid(), and any.valid() as the first value to reset any previously set values.

Joi.valid(1).valid(Joi.override, 2);

// Same as:

Joi.valid(2);

// Whereas:

Joi.valid(1).valid(2);

// Is the same as:

Joi.valid(1, 2);

ref(key, [options])

Generates a reference to the value of the named key. References are resolved at validation time and in order of dependency so that if one key validation depends on another, the dependent key is validated second after the reference is validated.

References support the following arguments:

Note that references can only be used where explicitly supported such as in valid() or invalid() rules. If upwards (parents) references are needed, use object.assert().

const schema = Joi.object({
    a: Joi.ref('b.c'),
    b: {
        c: Joi.any()
    },
    c: Joi.ref('$x')
});

await schema.validateAsync({ a: 5, b: { c: 5 } }, { context: { x: 5 } });

Relative references

By default, a reference is relative to the parent of the current value (the reference key is lookup
up inside the parent). This means that in the schema:

{
    x: {
        a: Joi.any(),
        b: {
            c: Joi.any(),
            d: Joi.ref('c')
        }
    },
    y: Joi.any()
}

The reference Joi.ref('c') points to c which is a sibling of d - the reference starting point
is d's parent which is b. This schema means that d must be equal to c.

In order to reference a parent peer, you can use a separator prefix where (using . as separator):

For example:

{
    x: {
        a: Joi.any(),
        b: {
            c: Joi.any(),
            d: Joi.ref('c'),
            e: Joi.ref('...a'),
            f: Joi.ref('....y')
        }
    },
    y: Joi.any()
}

Another way to specify the relative starting point is using the ancestor option where:

For example:

{
    x: {
        a: Joi.any(),
        b: {
            c: Joi.any(),
            d: Joi.ref('c', { ancestor: 1 }),
            e: Joi.ref('a', { ancestor: 2 }),
            f: Joi.ref('y', { ancestor: 3 })
        }
    },
    y: Joi.any()
}

Note that if a reference tries to reach beyond the value root, validation fails.

To specify an absolute path from the value root, use the / prefix:

{
    x: {
        a: Joi.any(),
        b: {
            c: Joi.ref('/x.a')
        }
    }
}

version

Property showing the current version of joi being used.

types()

Returns an object where each key is a plain joi schema type. Useful for creating type shortcuts
using deconstruction. Note that the types are already formed and do not need to be called as
functions (e.g. string, not string()).

const Joi = require('@hapi/joi');
const { object, string } = Joi.types();

const schema = object.keys({
  property: string.min(4)
});

any

Generates a schema object that matches any data type.

const any = Joi.any();
await any.validateAsync('a');

any.type

Gets the type of the schema.

const schema = Joi.string();

schema.type === 'string';   // === true

any.allow(...values)

Allows values where:

Note that this list of allowed values is in addition to any other permitted values.
To create an exclusive list of values, see any.valid(value).

const schema = {
    a: Joi.any().allow('a'),
    b: Joi.any().allow('b', 'B')
};

any.alter(targets)

Assign target alteration options to a schema that are applied when any.tailor()
is called where:

const schema = Joi.object({
    key: Joi.string()
        .alter({
            get: (schema) => schema.required(),
            post: (schema) => schema.forbidden()
        })  
});

const getSchema = schema.tailor('get');
const postSchema = schema.tailor('post');

any.cache([cache])

Adds caching to the schema which will attempt to cache the validation results (success and
failures) of incoming inputs where:

Note that deciding which inputs to cache is left to the cache implementation. The built-in
cache will only store simple values such as undefined, null, strings, numbers, and booleans.
Any changes to the schema after any.cache() is called will disable caching on the resulting
schema. this means that if .cache() is not the last statement in a schema definition, caching
will be disabled.

To disable caching for an entire schema in runtime, pass the cache preference set to false.

Caching ignores changes to runtime preference. This means that if you run schema.validatate()
onces using one set of preferences, and then again using another set (for example, changing the
language), the cached results will be based on the first set of preferences.

Before using caching, it is recommended to consider the performance gain as it will not speed up
every schema. Schemas using .valid() list will not benefit from caching.

Caching will be ignored when the schema uses references outside of the value scope.

Cache interface

Custom cache implementation must implement the following interface:

class {
    set(key, value) {}
    get(key) { return found ? value : undefined; }
}

Note that key and value can be anything including objects, array, etc. It is recommended to limit the size of the cache when validating external data in order to prevent an attacker from increasing the process memory usage by sending large amount of different data to validate.

any.cast(to)

Casts the validated value to the specified type where:

any.concat(schema)

Returns a new type that is the result of adding the rules of one type to another where:

const a = Joi.string().valid('a');
const b = Joi.string().valid('b');
const ab = a.concat(b);

any.custom(method, [description])

Adds a custom validation function to execute arbitrary code where:

Note: if the method fails to return a value, the value will be unset or returned as undefined.

const method = (value, helpers) => {

    // Throw an error (will be replaced with 'any.custom' error)
    if (value === '1') {
        throw new Error('nope');
    }

    // Replace value with a new value
    if (value === '2') {
        return '3';
    }

    // Use error to return an existing error code
    if (value === '4') {
        return helpers.error('any.invalid');
    }

    // Override value with undefined to unset
    if (value === '5') {
        return undefined;
    }

    // Return the value unchanged
    return value;
};

const schema = Joi.string().custom(method, 'custom validation');

Possible validation errors: any.custom

any.default([value])

Sets a default value if the original value is undefined where:

When called without any value on an object schema type, a default value will be automatically
generated based on the default values of the object keys.

Note that if value is an object, any changes to the object after default() is called will change
the reference and any future assignment. Use a function when setting a dynamic value (e.g. the
current time).

Using a function with a single argument performs some internal cloning which has a performance
impact. If you do not need access to the context, define the function without any arguments.

const generateUsername = (context) => {

  return context.firstname.toLowerCase() + '-' + context.lastname.toLowerCase();
};
generateUsername.description = 'generated username';

const schema = Joi.object({
    username: Joi.string().default(generateUsername),
    firstname: Joi.string(),
    lastname: Joi.string(),
    created: Joi.date().default(Date.now),
    status: Joi.string().default('registered')
});

const { value } = schema.validate({
    firstname: 'Jane',
    lastname: 'Doe'
});

// value.status === 'registered'
// value.username === 'jane-doe'
// value.created will be the time of validation

Possible validation errors: any.default

any.describe()

Returns an object that represents the internal configuration of the schema. Useful for debugging
and exposing a schema's configuration to other systems, like valid values in a user interface.

const schema = Joi.any().valid([ 'foo', 'bar' ]);
console.log(schema.describe());

Results in:

{ type: 'any',
  flags: { only: true },
  valids: [ 'foo', 'bar' ] }

any.description(desc)

Annotates the key where:

const schema = Joi.any().description('this key will match anything you give it');

any.empty(schema)

Considers anything that matches the schema to be empty (undefined).

let schema = Joi.string().empty('');
schema.validate(''); // returns { error: null, value: undefined }
schema = schema.empty();
schema.validate(''); // returns { error: "value" is not allowed to be empty, value: '' }

any.error(err)

Overrides the default joi error with a custom error if the rule fails where:

Do not use this method if you are simply trying to override the error message - use any.message() or any.messages() instead. This method is designed to override the joi validation error and return the exact override provided. It is useful when you want to return the result of validation directly (e.g. when using with a hapi server) and want to return a different HTTP error code than 400.

Note that if you provide an Error, it will be returned as-is, unmodified and undecorated with any of the normal error properties. If validation fails and another error is found before the error override, that error will be returned and the override will be ignored (unless the abortEarly option has been set to false). If you set multiple errors on a single schema, only the last error is used.

const schema = Joi.string().error(new Error('Was REALLY expecting a string'));
schema.validate(3);     // returns Error('Was REALLY expecting a string')
const schema = Joi.object({
    foo: Joi.number().min(0).error((errors) => new Error('"foo" requires a positive number'))
});
schema.validate({ foo: -2 });    // returns new Error('"foo" requires a positive number')
const schema = Joi.object({
    foo: Joi.number().min(0).error((errors) => {

        return new Error('found errors with ' + errors.map((err) => `${err.type}(${err.local.limit}) with value ${err.local.value}`).join(' and '));
    })
});
schema.validate({ foo: -2 });    // returns new Error('child "foo" fails because [found errors with number.min(0) with value -2]')

any.example(example, [options])

Adds examples to the schema where:

const schema = Joi.string().min(4).example('abcd');

any.external(method, [description])

Adds an external validation rule where:

Note that external validation rules are only called after the all other validation rules for the
entire schema (from the value root) are checked. This means that any changes made to the value by
the external rules are not available to any other validation rules during the non-external
validation phase.

If schema validation failed, no external validation rules are called.

any.extract(path)

Returns a sub-schema based on a path of object keys or schema ids where:

const schema = Joi.object({ foo: Joi.object({ bar: Joi.number() }) });
const number = schema.extract('foo.bar');

//or
const result = schema.extract(['foo', 'bar']); //same as number

any.failover(value)

Sets a failover value if the original value fails passing validation where:

Note that if value is an object, any changes to the object after failover() is called will change
the reference and any future assignment. Use a function when setting a dynamic value (e.g. the
current time).

Using a function with a single argument performs some internal cloning which has a performance
impact. If you do not need access to the context, define the function without any arguments.

Possible validation errors: any.failover

any.forbidden()

Marks a key as forbidden which will not allow any value except undefined. Used to explicitly forbid keys.

const schema = {
    a: Joi.any().forbidden()
};

Possible validation errors: any.unknown

any.fork(paths, adjuster)

Returns a new schema where each of the path keys listed have been modified where:

The method does not modify the original schema.

any.id(id)

Sets a schema id for reaching into the schema via any.extract() where:

If no id is set, the schema id defaults to the object key it is associated with. If the schema is
used in an array or alternatives type and no id is set, the schema in unreachable.

any.invalid(...values) - aliases: disallow, not

Disallows values where:

const schema = {
    a: Joi.any().invalid('a'),
    b: Joi.any().invalid('b', 'B')
};

Possible validation errors: any.invalid

any.keep()

Same as rule({ keep: true }).

Note that keep() will terminate the current ruleset and cannot be followed by another
rule option. Use rule() to apply multiple rule options.

any.label(name)

Overrides the key name in error messages.

const schema = {
    first_name: Joi.string().label('First Name')
};

any.message(message)

Same as rule({ message }).

Note that message() will terminate the current ruleset and cannot be followed by another
rule option. Use rule() to apply multiple rule options.

any.messages(messages)

Same as any.prefs({ messages }).

Note that while any.message() applies only to the last rule or ruleset, any.messages() applies to the entire schema.

any.meta(meta)

Attaches metadata to the key where:

const schema = Joi.any().meta({ index: true });

any.note(...notes)

Annotates the key where:

const schema = Joi.any().note('this is special', 'this is important');

any.only()

Requires the validated value to match of the provided any.allow() values. It has not effect when
called together with any.valid() since it already sets the requirements. When used with
any.allow() it converts it to an any.valid().

any.optional()

Marks a key as optional which will allow undefined as values. Used to annotate the schema for readability as all keys are optional by default.

Note: this does not allow a null value. To do that, use any.allow(value). Or both!

const schema = Joi.any().optional();

any.prefs(options) - aliases: preferences, options

Overrides the global validate() options for the current key and any sub-key where:

const schema = Joi.any().prefs({ convert: false });

any.presence(mode)

Sets the presence mode for the schema where:

Same as calling any.optional(), any.required(), or any.forbidden().

any.raw([enabled])

Outputs the original untouched value instead of the casted value where:

Note that the raw value is only applied after validation and any references to the value use the
validated value, not the raw value.

const timestampSchema = Joi.date().timestamp();
timestampSchema.validate('12376834097810'); // { error: null, value: Sat Mar 17 2362 04:28:17 GMT-0500 (CDT) }

const rawTimestampSchema = Joi.date().timestamp().raw();
rawTimestampSchema.validate('12376834097810'); // { error: null, value: '12376834097810' }

any.required() - aliases: exist

Marks a key as required which will not allow undefined as value. All keys are optional by default.

const schema = Joi.any().required();

Possible validation errors: any.required

any.result(mode)

Set the result mode where:

any.rule(options)

Applies a set of rule options to the current ruleset or last rule added where:

When applying rule options, the last rule (e.g. min()) is used unless there is an active ruleset defined (e.g. $.min().max()) in which case the options are applied to all the provided rules. Once rule() is called, the previous rules can no longer be modified and any active ruleset is terminated.

Rule modifications can only be applied to supported rules. Most of the any methods do not support rule modifications because they are implemented using schema flags (e.g. required()) or special internal implementation (e.g. valid()). In those cases, use the any.messages() method to override the error codes for the errors you want to customize.

any.ruleset - aliases: $

Starts a ruleset in order to apply multiple rule options. The set ends when
rule(), keep(), message(), or warn() is called.

const schema = Joi.number().ruleset.min(1).max(10).rule({ message: 'Number must be between 1 and 10' });
const schema = Joi.number().$.min(1).max(10).rule({ message: 'Number must be between 1 and 10' });

any.shared(schema)

Registers a schema to be used by decendents of the current schema in named link references, where:

  const schema = Joi.object({
      a: [Joi.string(), Joi.link('#x')],
      b: Joi.link('#type.a')
  })
      .shared(Joi.number().id('x'))
      .id('type');

any.strict(isStrict)

Strict mode sets the options.convert options to false which prevent type casting for the current key and any child keys.

const schema = Joi.any().strict();

any.strip([enabled])

Marks a key to be removed from a resulting object or array after validation to sanitize the output
where:

const schema = Joi.object({
    username: Joi.string(),
    password: Joi.string().strip()
});

schema.validate({ username: 'test', password: 'hunter2' }); // result.value = { username: 'test' }

const schema = Joi.array().items(Joi.string(), Joi.any().strip());

schema.validate(['one', 'two', true, false, 1, 2]); // result.value = ['one', 'two']
});

any.tag(...tags)

Annotates the key where:

const schema = Joi.any().tag('api', 'user');

any.tailor(targets)

Applies any assigned target alterations to a copy of the schema that were applied via
any.alter() where:

const schema = Joi.object({
    key: Joi.string()
        .alter({
            get: (schema) => schema.required(),
            post: (schema) => schema.forbidden()
        })  
});

const getSchema = schema.tailor('get');
const postSchema = schema.tailor(['post']);

any.unit(name)

Annotates the key where:

const schema = Joi.number().unit('milliseconds');

any.valid(...values) - aliases: equal

Adds the provided values into the allowed values list and marks them as the only valid values allowed where:

const schema = {
    a: Joi.any().valid('a'),
    b: Joi.any().valid('b', 'B')
};

Possible validation errors: any.only

any.validate(value, [options])

Validates a value using the current schema and options where:

Returns an object with the following keys:

const schema = Joi.object({
    a: Joi.number()
});

const value = {
    a: '123'
};

const result = schema.validate(value);
// result -> { value: { "a" : 123 } }

any.validateAsync(value, [options])

Validates a value asynchronously using the current schema and options where:

Returns a Promise.

const schema = Joi.object({
    a: Joi.number()
});

const value = {
    a: '123'
};

try {
  const value = await schema.validateAsync(value);
  // value -> { "a" : 123 }
}
catch (err) {
}

any.warn()

Same as rule({ warn: true }).

Note that warn() will terminate the current ruleset and cannot be followed by another
rule option. Use rule() to apply multiple rule options.

any.warning(code, [context])

Generates a warning where:

When calling any.validateAsync(), set the warning option to true
to enable warnings. Warnings are reported separately from errors alongside the result value via the
warning key (i.e. { value, warning }). Warning are always included when calling
any.validate().

const schema = Joi.any()
    .warning('custom.x', { w: 'world' })
    .message({ 'custom.x': 'hello {#w}!' });

const { value, error, warning } = schema.validate('anything');

// value -> 'anything';
// error -> null
// warning -> { message: 'hello world!', details: [...] }

// or

try {
    const { value, warning } = await schema.validateAsync('anything', { warnings: true });
    // value -> 'anything';
    // warning -> { message: 'hello world!', details: [...] }
}
catch (err) { }

any.when([condition], options)

Adds conditions that are evaluated during validation and modify the schema before it is applied to the value, where:

If condition is a reference:

If condition is a schema:

When is, then, or otherwise are assigned literal values, the values are compiled into override schemas ('x' is compiled into Joi.valid(Joi.override, 'x')). This means they will override any base schema the rule is applied to. To append a literal value, use the explicit Joi.valid('x') format.

Notes:

const schema = {
    a: Joi.any()
        .valid('x')
        .when('b', { is: Joi.exist(), then: Joi.valid('y'), otherwise: Joi.valid('z') })
        .when('c', { is: Joi.number().min(10), then: Joi.forbidden() }),
    b: Joi.any(),
    c: Joi.number()
};

Or with a schema:

const schema = Joi.object({
    a: Joi.any().valid('x'),
    b: Joi.any()
})
    .when(Joi.object({ b: Joi.exist() }).unknown(), {
        then: Joi.object({
            a: Joi.valid('y')
        }),
        otherwise: Joi.object({
            a: Joi.valid('z')
        })
});

Note that this style is much more useful when your whole schema depends on the value of one of its
property, or if you find yourself repeating the check for many keys of an object. For example to
validate this logic:

const schema = Joi.object({
    type: Joi.string()
        .valid('A', 'B', 'C')
        .required(),              // required if type == 'A'

    foo: Joi.when('type', {
        is: 'A',
        then: Joi.string()
        .valid('X', 'Y', 'Z')
        .required()
    }),                           // required if type === 'A' and foo !== 'Z'

    bar: Joi.string()
})
    .when(Joi.object({ type: Joi.valid('A'), foo: Joi.not('Z') }).unknown(), {
        then: Joi.object({ bar: Joi.required() })
    });

Alternatively, if you want to specify a specific type such as string, array, etc, you can do so
like this:

const schema = {
    a: Joi.valid('a', 'b', 'other'),
    other: Joi.string()
        .when('a', { is: 'other', then: Joi.required() }),
};

If you need to validate a child key inside a nested object based on a sibling's value, you can do
so like this:

const schema = Joi.object({
    a: Joi.boolean().required(),
    b: Joi.object()
        .keys({
            c: Joi.string(),
            d: Joi.number().required()
        })
        .required()
        .when('a', {
            is: true,
            then: Joi.object({ c: Joi.required() })        // b.c is required only when a is true
        })
});

If you want to validate one key based on the existence of another key, you can do so like the
following (notice the use of required()):

const schema = Joi.object({
    min: Joi.number(),
    max: Joi.number().when('min', {
        is: Joi.number().required(),
        then: Joi.number().greater(Joi.ref('min')),
    }),
});

To evaluate multiple values on a single reference:

const schema = Joi.object({
    a: Joi.number().required(),
    b: Joi.number()
        .when('a', {
            switch: [
                { is: 0, then: Joi.valid(1) },
                { is: 1, then: Joi.valid(2) },
                { is: 2, then: Joi.valid(3) }
            ],
            otherwise: Joi.valid(4)
        })
});

Or shorter:

const schema = Joi.object({
    a: Joi.number().required(),
    b: Joi.number()
        .when('a', [
            { is: 0, then: 1 },
            { is: 1, then: 2 },
            { is: 2, then: 3, otherwise: 4 }
        ])
});

alternatives

Generates a type that will match one of the provided alternative schemas via the try()
method. If no schemas are added, the type will not match any value except for undefined.

Supports the same methods of the any() type.

Alternatives can be expressed using the shorter [] notation.

const alt = Joi.alternatives().try(Joi.number(), Joi.string());
// Same as [Joi.number(), Joi.string()]

Possible validation errors: alternatives.any, alternatives.all, alternatives.one, alternatives.types, alternatives.match

alternatives.conditional(condition, options)

Adds a conditional alternative schema type, either based on another key value, or a schema peeking into the current value, where:

If condition is a reference:

If condition is a schema:

When is, then, or otherwise are assigned literal values, the values are compiled into override schemas ('x' is compiled into Joi.valid(Joi.override, 'x')). This means they will override any base schema the rule is applied to. To append a literal value, use the explicit Joi.valid('x') format.

Note that alternatives.conditional() is different than any.when(). When you use any.when() you end up with composite schema of all the matching conditions while alternatives.conditional() will use the first matching schema, ignoring other conditional statements.

const schema = {
    a: Joi.alternatives().conditional('b', { is: 5, then: Joi.string(), otherwise: Joi.number() }),
    b: Joi.any()
};
const schema = Joi.alternatives().conditional(Joi.object({ b: 5 }).unknown(), {
    then: Joi.object({
        a: Joi.string(),
        b: Joi.any()
    }),
    otherwise: Joi.object({
        a: Joi.number(),
        b: Joi.any()
    })
});

Note that conditional() only adds additional alternatives to try and does not impact the overall type. Setting
a required() rule on a single alternative will not apply to the overall key. For example,
this definition of a:

const schema = {
    a: Joi.alternatives().conditional('b', { is: true, then: Joi.required() }),
    b: Joi.boolean()
};

Does not turn a into a required key when b is true. Instead, it tells the validator to try and match the
value to anything that's not undefined. However, since Joi.alternatives() by itself allows undefined, the rule
does not accomplish turning a to a required value. This rule is the same as Joi.alternatives([Joi.required()])
when b is true which will allow any value including undefined.

To accomplish the desired result above use:

const schema = {
    a: Joi.conditional('b', { is: true, then: Joi.required() }),
    b: Joi.boolean()
};

alternatives.match(mode)

Requires the validated value to match a specific set of the provided alternative.try() schemas where:

Note: Cannot be combined with alternatives.conditional().

Possible validation errors: alternatives.any, alternatives.all, alternatives.one

alternatives.try(...schemas)

Adds an alternative schema type for attempting to match against the validated value where:

const alt = Joi.alternatives().try(Joi.number(), Joi.string());
await alt.validateAsync('a');

array

Generates a schema object that matches an array data type. Note that undefined values inside arrays are not allowed by
default but can be by using sparse().

Supports the same methods of the any() type.

const array = Joi.array().items(Joi.string().valid('a', 'b'));
await array.validateAsync(['a', 'b', 'a']);

Possible validation errors: array.base

array.has(schema)

Verifies that a schema validates at least one of the values in the array, where:

const schema = Joi.array().items(
  Joi.object({
    a: Joi.string(),
    b: Joi.number()
  })
).has(Joi.object({ a: Joi.string().valid('a'), b: Joi.number() }))

Possible validation errors: array.hasKnown, array.hasUnknown

array.items(...types)

Lists the types allowed for the array values where:

If a given type is .required() then there must be a matching item in the array.
If a type is .forbidden() then it cannot appear in the array.
Required items can be added multiple times to signify that multiple items must be found.
Errors will contain the number of items that didn't match. Any unmatched item having a label will be mentioned explicitly.

const schema = Joi.array().items(Joi.string(), Joi.number()); // array may contain strings and numbers
const schema = Joi.array().items(Joi.string().required(), Joi.string().required()); // array must contain at least two strings
const schema = Joi.array().items(Joi.string().valid('not allowed').forbidden(), Joi.string()); // array may contain strings, but none of those strings can match 'not allowed'
const schema = Joi.array().items(Joi.string().label('My string').required(), Joi.number().required()); // If this fails it can result in `[ValidationError: "value" does not contain [My string] and 1 other required value(s)]`

Possible validation errors: array.excludes, [array.includesRequiredBoth], [array.includesRequiredKnowns], [array.includesRequiredUnknowns], array.includes

array.length(limit)

Specifies the exact number of items in the array where:

const schema = Joi.array().length(5);
const schema = Joi.object({
  limit: Joi.number().integer().required(),
  numbers: Joi.array().length(Joi.ref('limit')).required()
});

Possible validation errors: array.length, array.ref

array.max(limit)

Specifies the maximum number of items in the array where:

const schema = Joi.array().max(10);
const schema = Joi.object({
  limit: Joi.number().integer().required(),
  numbers: Joi.array().max(Joi.ref('limit')).required()
});

Possible validation errors: array.max, array.ref

array.min(limit)

Specifies the minimum number of items in the array where:

const schema = Joi.array().min(2);
const schema = Joi.object({
  limit: Joi.number().integer().required(),
  numbers: Joi.array().min(Joi.ref('limit')).required()
});

Possible validation errors: array.min, array.ref

array.ordered(...type)

Lists the types in sequence order for the array values where:

If a given type is .required() then there must be a matching item with the same index position in the array.
Errors will contain the number of items that didn't match. Any unmatched item having a label will be mentioned explicitly.

const schema = Joi.array().ordered(Joi.string().required(), Joi.number().required()); // array must have first item as string and second item as number
const schema = Joi.array().ordered(Joi.string().required()).items(Joi.number().required()); // array must have first item as string and 1 or more subsequent items as number
const schema = Joi.array().ordered(Joi.string().required(), Joi.number()); // array must have first item as string and optionally second item as number

Possible validation errors: array.excludes, array.includes, array.orderedLength

array.single([enabled])

Allows single values to be checked against rules as if it were provided as an array.

enabled can be used with a falsy value to go back to the default behavior.

const schema = Joi.array().items(Joi.number()).single();
schema.validate([4]); // returns `{ error: null, value: [ 4 ] }`
schema.validate(4); // returns `{ error: null, value: [ 4 ] }`

Possible validation errors: array.excludes, array.includes

array.sort([options])

Requires the array to comply with the specified sort order where:

Notes:

Possible validation errors: array.sort, array.sort.unsupported, array.sort.mismatching

array.sparse([enabled])

Allows this array to be sparse. enabled can be used with a falsy value to go back to the default behavior.

let schema = Joi.array().sparse(); // undefined values are now allowed
schema = schema.sparse(false); // undefined values are now denied

Possible validation errors: array.sparse

array.unique([comparator, [options]])

Requires the array values to be unique where:

Note: remember that if you provide a custom comparator function, different types can be passed as parameter depending on the rules you set on items.

Be aware that a deep equality is performed on elements of the array having a type of object, a performance penalty is to be expected for this kind of operation.

const schema = Joi.array().unique();
const schema = Joi.array().unique((a, b) => a.property === b.property);
const schema = Joi.array().unique('customer.id');
let schema = Joi.array().unique('identifier');

schema.validate([{}, {}]);
// ValidationError: "value" position 1 contains a duplicate value

schema = Joi.array().unique('identifier', { ignoreUndefined: true });

schema.validate([{}, {}]);
// error: null

Possible validation errors: array.unique

binary

Generates a schema object that matches a Buffer data type. If the validation convert option is on (enabled by default), a string
will be converted to a Buffer if specified.

Supports the same methods of the any() type.

const schema = Joi.binary();

Possible validation errors: binary.base

binary.encoding(encoding)

Sets the string encoding format if a string input is converted to a buffer where:

const schema = Joi.binary().encoding('base64');

binary.length(limit)

Specifies the exact length of the buffer:

const schema = Joi.binary().length(5);

Possible validation errors: binary.length, binary.ref

binary.max(limit)

Specifies the maximum length of the buffer where:

const schema = Joi.binary().max(10);

Possible validation errors: binary.max, binary.ref

binary.min(limit)

Specifies the minimum length of the buffer where:

const schema = Joi.binary().min(2);

Possible validation errors: binary.min, binary.ref

boolean

Generates a schema object that matches a boolean data type. Can also be called via bool(). If the validation convert
option is on (enabled by default), a string (either "true" or "false") will be converted to a boolean if specified.

Supports the same methods of the any() type.

const boolean = Joi.boolean();

await boolean.validateAsync(true); // Valid
await boolean.validateAsync(1);    // Throws

Possible validation errors: boolean.base

boolean.falsy(...values)

Allows for additional values to be considered valid booleans by converting them to false during validation.
Requires the validation convert option to be true.

String comparisons are by default case insensitive, see boolean.sensitive() to change this behavior.

const boolean = Joi.boolean().falsy('N');
await boolean.validateAsync('N'); // Valid

boolean.sensitive([enabled])

Restrict the values provided to truthy and falsy as well as the 'true' and 'false' default conversions (when not in strict() mode) to be matched in a case sensitive manner, where:

const schema = Joi.boolean().truthy('yes').falsy('no').sensitive();

boolean.truthy(...values)

Allows for additional values to be considered valid booleans by converting them to true during validation.
Requires the validation convert option to be true.

String comparisons are by default case insensitive, see boolean.sensitive() to change this behavior.

const boolean = Joi.boolean().truthy('Y');
await boolean.validateAsync('Y'); // Valid

date

Generates a schema object that matches a date type (as well as a JavaScript date string or number of milliseconds). If
the validation convert option is on (enabled by default), a string or number will be converted to a Date if specified.

Supports the same methods of the any() type.

const date = Joi.date();
await date.validateAsync('12-21-2012');

Possible validation errors: date.base, date.strict

date.greater(date)

Specifies that the value must be greater than date (or a reference).

const schema = Joi.date().greater('1-1-1974');

Notes: 'now' can be passed in lieu of date so as to always compare relatively to the current date, allowing to explicitly ensure a date is either in the past or in the future.

const schema = Joi.date().greater('now');
const schema = Joi.object({
  from: Joi.date().required(),
  to: Joi.date().greater(Joi.ref('from')).required()
});

Possible validation errors: date.greater, date.ref

date.iso()

Requires the string value to be in valid ISO 8601 date format.

const schema = Joi.date().iso();

Possible validation errors: date.format

date.less(date)

Specifies that the value must be less than date (or a reference).

const schema = Joi.date().less('12-31-2020');

Notes: 'now' can be passed in lieu of date so as to always compare relatively to the current date, allowing to explicitly ensure a date is either in the past or in the future.

const schema = Joi.date().max('now');
const schema = Joi.object({
  from: Joi.date().less(Joi.ref('to')).required(),
  to: Joi.date().required()
});

Possible validation errors: date.less, date.ref

date.max(date)

Specifies the latest date allowed where:

const schema = Joi.date().max('12-31-2020');

Notes: 'now' can be passed in lieu of date so as to always compare relatively to the current date, allowing to explicitly ensure a date is either in the past or in the future.

const schema = Joi.date().max('now');
const schema = Joi.object({
  from: Joi.date().max(Joi.ref('to')).required(),
  to: Joi.date().required()
});

Possible validation errors: date.max, date.ref

date.min(date)

Specifies the oldest date allowed where:

const schema = Joi.date().min('1-1-1974');

Notes: 'now' can be passed in lieu of date so as to always compare relatively to the current date, allowing to explicitly ensure a date is either in the past or in the future.

const schema = Joi.date().min('now');
const schema = Joi.object({
  from: Joi.date().required(),
  to: Joi.date().min(Joi.ref('from')).required()
});

Possible validation errors: date.min, date.ref

date.timestamp([type])

Requires the value to be a timestamp interval from Unix Time.

const schema = Joi.date().timestamp(); // defaults to javascript timestamp
const schema = Joi.date().timestamp('javascript'); // also, for javascript timestamp (milliseconds)
const schema = Joi.date().timestamp('unix'); // for unix timestamp (seconds)

Possible validation errors: date.format

function - inherits from object

Generates a schema object that matches a function type.

Supports the same methods of the object() type. Note that validating a function keys will cause the function
to be cloned. While the function will retain its prototype and closure, it will lose its length property value (will be
set to 0).

const func = Joi.function();
await func.validateAsync(function () {});

Possible validation errors: object.base

function.arity(n)

Specifies the arity of the function where:

const schema = Joi.function().arity(2);

Possible validation errors: function.arity

function.class()

Requires the function to be a class.

const schema = Joi.function().class();

Possible validation errors: function.class

function.maxArity(n)

Specifies the maximal arity of the function where:

const schema = Joi.function().maxArity(3);

Possible validation errors: function.maxArity

function.minArity(n)

Specifies the minimal arity of the function where:

const schema = Joi.function().minArity(1);

Possible validation errors: function.minArity

link(ref)

Links to another schema node and reuses it for validation, typically for creative recursive schemas, where:

Supports the methods of the any() type.

When links are combined with any.when() rules, the rules are applied after the link is resolved to the linked schema.

Names links are recommended for most use cases as they are easy to reason and understand, and when mistakes are made, they simply error with invalid link message. Relative links are often hard to follow, especially when they are nested in array or alternatives rules. Absolute links are useful only when the schema is never reused inside another schema as the root is the run-time root of the schema being validated, not the current schema root.

Note that named links must be found in a direct ancestor of the link. The names are searched by iterating over the chain of schemas from the current schema to the root. To reach an uncle or cousin, you must use the name of a common ancestor such as a grandparent and then walk down the tree.

Links are resolved once (per runtime) and the result schema cached. If you reuse a link in different places, the first time it is resolved at run-time, the result will be used by all other instances. If you want each link to resolve relative to the place it is used, use a separate Joi.link() statement in each place or set the relative() flag.

Named links:

const person = Joi.object({
    firstName: Joi.string().required(),
    lastName: Joi.string().required(),
    children: Joi.array()
        .items(Joi.link('#person'))
})
  .id('person');

Relative links:

const person = Joi.object({
    firstName: Joi.string().required(),
    lastName: Joi.string().required(),
    children: Joi.array()
        .items(Joi.link('...'))
        // . - the link
        // .. - the children array
        // ... - the person object
});

Absolute links:

const person = Joi.object({
    firstName: Joi.string().required(),
    lastName: Joi.string().required(),
    children: Joi.array()
        .items(Joi.link('/'))
});

link.ref(ref)

Initializes the schema after constructions for cases where the schema has to be constructed first and
then initialized. If ref was not passed to the constructor, link.ref() must be called prior to usaged.

Will throw an error during validation if left uninitialized (e.g. Joi.link() called without a link and link.ref() not called).

link.concat(schema)

Same as any.concat() but the schema is merged after the link is resolved which allows merging with schemas of the same type as the resolved link. Will throw an exception during validation if the merged types are not compatible.

number

Generates a schema object that matches a number data type (as well as strings that can be converted to numbers).

By default, it only allows safe numbers, see number.unsafe().

If the validation convert option is on (enabled by default), a string will be converted to a number if specified. Also, if
convert is on and number.precision() is used, the value will be converted to the specified precision as well.

Infinity and -Infinity are invalid by default, you can change that behavior by calling allow(Infinity, -Infinity).

Supports the same methods of the any() type.

const number = Joi.number();
await number.validateAsync(5);

Possible validation errors: number.base, number.infinity

number.greater(limit)

Specifies that the value must be greater than limit or a reference.

const schema = Joi.number().greater(5);
const schema = Joi.object({
  min: Joi.number().required(),
  max: Joi.number().greater(Joi.ref('min')).required()
});

Possible validation errors: number.greater, number.ref

number.integer()

Requires the number to be an integer (no floating point).

const schema = Joi.number().integer();

Possible validation errors: number.base

number.less(limit)

Specifies that the value must be less than limit or a reference.

const schema = Joi.number().less(10);
const schema = Joi.object({
  min: Joi.number().less(Joi.ref('max')).required(),
  max: Joi.number().required()
});

Possible validation errors: number.less, number.ref

number.max(limit)

Specifies the maximum value where:

const schema = Joi.number().max(10);
const schema = Joi.object({
  min: Joi.number().max(Joi.ref('max')).required(),
  max: Joi.number().required()
});

Possible validation errors: number.max, number.ref

number.min(limit)

Specifies the minimum value where:

const schema = Joi.number().min(2);
const schema = Joi.object({
  min: Joi.number().required(),
  max: Joi.number().min(Joi.ref('min')).required()
});

Possible validation errors: number.min, number.ref

number.multiple(base)

Specifies that the value must be a multiple of base (or a reference):

const schema = Joi.number().multiple(3);

Notes: Joi.number.multiple(base) uses the modulo operator (%) to determine if a number is multiple of another number. Therefore, it has the normal limitations of Javascript modulo operator. The results with decimal/floats may be incorrect.

Possible validation errors: number.multiple, number.ref

number.negative()

Requires the number to be negative.

const schema = Joi.number().negative();

Possible validation errors: number.negative

number.port()

Requires the number to be a TCP port, so between 0 and 65535.

const schema = Joi.number().port();

Possible validation errors: number.port

number.positive()

Requires the number to be positive.

const schema = Joi.number().positive();

Possible validation errors: number.positive

number.precision(limit)

Specifies the maximum number of decimal places where:

const schema = Joi.number().precision(2);

Possible validation errors: number.integer

number.sign(sign)

Requires the number to be negative or positive where:
sign - one of 'negative' or 'positive'.

Possible validation errors: number.negative, number.positive

number.unsafe([enabled])

By default, numbers must be within JavaScript's safety range (Number.MIN_SAFE_INTEGER & Number.MAX_SAFE_INTEGER), and when given a string, should be converted without loss of information. You can allow unsafe numbers at your own risks by calling number.unsafe().

Parameters are:

const safeNumber = Joi.number();
safeNumber.validate(90071992547409924);
// error -> "value" must be a safe number

const unsafeNumber = Joi.number().unsafe();
unsafeNumber.validate(90071992547409924);
// error -> null
// value -> 90071992547409920

Possible validation errors: number.unsafe

object

Generates a schema object that matches an object data type (as well as JSON strings that parsed into objects). Defaults
to allowing any child key.

Supports the same methods of the any() type.

const object = Joi.object({
    a: Joi.number().min(1).max(10).integer(),
    b: 'some string'
});

await object.validateAsync({ a: 5 });

Note that when an object schema type is passed as an input to another joi method (e.g. array
item) or is set as a key definition, the Joi.object() constructor may be omitted. For example:

const schema = Joi.array().items({ a: Joi.string() });

Possible validation errors: object.base

object.and(...peers, [options])

Defines an all-or-nothing relationship between keys where if one of the peers is present, all of
them are required as well where:

const schema = Joi.object({
    a: Joi.any(),
    b: Joi.any()
}).and('a', 'b');

Possible validation errors: object.and

object.append([schema])

Appends the allowed object keys where:

// Validate key a
const base = Joi.object({
    a: Joi.number()
});
// Validate keys a, b.
const extended = base.append({
    b: Joi.string()
});

object.assert(subject, schema, [message])

Verifies an assertion where:

const schema = Joi.object({
    a: {
        b: Joi.string(),
        c: Joi.number()
    },
    d: {
        e: Joi.any()
    }
}).assert('.d.e', Joi.ref('a.c'), 'equal to a.c');

Possible validation errors: object.assert

object.instance(constructor, [name])

Requires the object to be an instance of a given constructor where:

const schema = Joi.object().instance(RegExp);

Possible validation errors: object.instance

object.keys([schema])

Sets or extends the allowed object keys where:

const base = Joi.object().keys({
    a: Joi.number(),
    b: Joi.string()
});
// Validate keys a, b and c.
const extended = base.keys({
    c: Joi.boolean()
});

Possible validation errors: object.unknown

object.length(limit)

Specifies the exact number of keys in the object where or a reference:

const schema = Joi.object().length(5);

Possible validation errors: object.length, object.ref

object.max(limit)

Specifies the maximum number of keys in the object where:

const schema = Joi.object().max(10);

Possible validation errors: object.max, object.ref

object.min(limit)

Specifies the minimum number of keys in the object where:

const schema = Joi.object().min(2);

Possible validation errors: object.min, object.ref

object.nand(...peers, [options])

Defines a relationship between keys where not all peers can be present at the same time where:

const schema = Joi.object({
    a: Joi.any(),
    b: Joi.any()
}).nand('a', 'b');

Possible validation errors: object.nand

object.or(...peers, [options])

Defines a relationship between keys where one of the peers is required (and more than one is
allowed) where:

const schema = Joi.object({
    a: Joi.any(),
    b: Joi.any()
}).or('a', 'b');

Possible validation errors: object.missing

object.oxor(...peers, [options])

Defines an exclusive relationship between a set of keys where only one is allowed but none are
required where:

const schema = Joi.object({
    a: Joi.any(),
    b: Joi.any()
}).oxor('a', 'b');

Possible validation errors: object.oxor

object.pattern(pattern, schema, [options])

Specify validation rules for unknown keys matching a pattern where:

const schema = Joi.object({
    a: Joi.string()
}).pattern(/\w\d/, Joi.boolean());

// OR

const schema = Joi.object({
    a: Joi.string()
}).pattern(Joi.string().min(2).max(5), Joi.boolean());

Possible validation errors: object.pattern.match

object.ref()

Requires the object to be a joi reference.

const schema = Joi.object().ref();

Possible validation errors: object.refType

object.rename(from, to, [options])

Renames a key to another name (deletes the renamed key) where:

Keys are renamed before any other validation rules are applied. If to is a template that
references the object own keys (e.g. '{.prefix}-{#1}'), the value of these keys is the raw
input value, not the value generated after validation.

const object = Joi.object({
    a: Joi.number()
}).rename('b', 'a');

await object.validateAsync({ b: 5 });

Using a regular expression:

const regex = /^foobar$/i;

const schema = Joi.object({
  fooBar: Joi.string()
}).rename(regex, 'fooBar');

await schema.validateAsync({ FooBar: 'a'});

Using a regular expression with template:

const schema = Joi.object()
    .rename(/^(\d+)$/, Joi.template('x{#1}x'))
    .pattern(/^x\d+x$/, Joi.any());

const input = {
    123: 'x',
    1: 'y',
    0: 'z',
    x4x: 'test'
};

const value = await Joi.compile(schema).validateAsync(input);
// value === { x123x: 'x', x1x: 'y', x0x: 'z', x4x: 'test' }

Possible validation errors: object.rename.multiple, object.rename.override

object.schema([type])

Requires the object to be a joi schema instance where:

const schema = Joi.object().schema();

Possible validation errors: object.schema

object.unknown([allow])

Overrides the handling of unknown keys for the scope of the current object only (does not apply to children) where:

const schema = Joi.object({ a: Joi.any() }).unknown();

Possible validation errors: object.unknown

object.with(key, peers, [options])

Requires the presence of other keys whenever the specified key is present where:

Note that unlike object.and(), with() creates a dependency only between the key and each of the peers, not
between the peers themselves.

const schema = Joi.object({
    a: Joi.any(),
    b: Joi.any()
}).with('a', 'b');

Possible validation errors: object.with

object.without(key, peers, [options])

Forbids the presence of other keys whenever the specified is present where:

const schema = Joi.object({
    a: Joi.any(),
    b: Joi.any()
}).without('a', ['b']);

Possible validation errors: object.without

object.xor(...peers, [options])

Defines an exclusive relationship between a set of keys where one of them is required but not at
the same time where:

const schema = Joi.object({
    a: Joi.any(),
    b: Joi.any()
}).xor('a', 'b');

Possible validation errors: object.xor, object.missing

string

Generates a schema object that matches a string data type.

Note that the empty string is not allowed by default and must be enabled with allow(''). Don't over think, just remember that the empty string is not a valid string by default. Also, don't ask to change it or argue why it doesn't make sense. This topic is closed.

To specify a default value in case of the empty string use:

Joi.string()
    .empty('')
    .default('default value');

If the convert preference is true (the default value), a string will be converted using the specified modifiers
for string.lowercase(), string.uppercase(), string.trim(), and each replacement specified with string.replace().

Supports the same methods of the any() type.

const schema = Joi.string().min(1).max(10);
await schema.validateAsync('12345');

Possible validation errors: string.base, string.empty

string.alphanum()

Requires the string value to only contain a-z, A-Z, and 0-9.

const schema = Joi.string().alphanum();

Possible validation errors: string.alphanum

string.base64([options])

Requires the string value to be a valid base64 string; does not check the decoded value.

Padding characters are not required for decoding, as the number of missing bytes can be inferred from the number of digits. With that said, try to use padding if at all possible.

const schema = Joi.string().base64();
schema.validate('VE9PTUFOWVNFQ1JFVFM'); // ValidationError: "value" must be a valid base64 string
schema.validate('VE9PTUFOWVNFQ1JFVFM='); // No Error

const paddingRequiredSchema = Joi.string().base64({ paddingRequired: true });
paddingRequiredSchema.validate('VE9PTUFOWVNFQ1JFVFM'); // ValidationError: "value" must be a valid base64 string
paddingRequiredSchema.validate('VE9PTUFOWVNFQ1JFVFM='); // No Error

const paddingOptionalSchema = Joi.string().base64({ paddingRequired: false });
paddingOptionalSchema.validate('VE9PTUFOWVNFQ1JFVFM'); // No Error
paddingOptionalSchema.validate('VE9PTUFOWVNFQ1JFVFM='); // No Error

Possible validation errors: string.base64

string.case(direction)

Sets the required string case where:

const schema = Joi.string().case('lower');

Possible validation errors: string.lowercase string.uppercase

string.creditCard()

Requires the number to be a credit card number (Using Luhn Algorithm).

const schema = Joi.string().creditCard();

Possible validation errors: string.creditCard

string.dataUri([options])

Requires the string value to be a valid data URI string.

const schema = Joi.string().dataUri();
schema.validate('VE9PTUFOWVNFQ1JFVFM='); // ValidationError: "value" must be a valid dataUri string
schema.validate('data:image/png;base64,VE9PTUFOWVNFQ1JFVFM='); // No Error

Possible validation errors: string.dataUri

string.domain([options])

Requires the string value to be a valid domain name.

const schema = Joi.string().domain();

Possible validation errors: string.domain

string.email([options])

Requires the string value to be a valid email address.

const schema = Joi.string().email();

Possible validation errors: string.email

string.guid() - aliases: uuid

Requires the string value to be a valid GUID.

const schema = Joi.string().guid({
    version: [
        'uuidv4',
        'uuidv5'
    ]
});

Possible validation errors: string.guid

string.hex([options])

Requires the string value to be a valid hexadecimal string.

const schema = Joi.string().hex();

Possible validation errors: string.hex, string.hexAlign

string.hostname()

Requires the string value to be a valid hostname as per RFC1123.

const schema = Joi.string().hostname();

Possible validation errors: string.hostname

string.insensitive()

Allows the value to match any value in the allowed list or disallowed list in a case insensitive comparison.

const schema = Joi.string().valid('a').insensitive();

string.ip([options])

Requires the string value to be a valid ip address.

// Accept only ipv4 and ipv6 addresses with a CIDR
const schema = Joi.string().ip({
  version: [
    'ipv4',
    'ipv6'
  ],
  cidr: 'required'
});

Possible validation errors: string.ip, string.ipVersion

string.isoDate()

Requires the string value to be in valid ISO 8601 date format.

If the validation convert option is on (enabled by default), the string will be forced to
simplified extended ISO format (ISO 8601). Be aware that this operation uses javascript Date
object, which does not support the full ISO format, so a few formats might not pass when using
convert.

const schema = Joi.string().isoDate();
schema.validate('2018-11-28T18:25:32+00:00'); // No Error
schema.validate('20181-11-28T18:25:32+00:00'); // ValidationError: must be a valid 8601 date
schema.validate(''); // ValidationError: must be a valid 8601 date

Possible validation errors: string.isoDate

string.isoDuration()

Requires the string value to be in valid ISO 8601 duration format.

const schema = Joi.string().isoDuration();
schema.validate('P3Y6M4DT12H30M5S'); // No Error
schema.validate('2018-11-28T18:25:32+00:00'); // ValidationError: must be a valid ISO 8601 duration
schema.validate(''); // ValidationError: must be a valid ISO 8601 duration

Possible validation errors: string.isoDuration

string.length(limit, [encoding])

Specifies the exact string length required where:

const schema = Joi.string().length(5);
const schema = Joi.object({
  length: Joi.string().required(),
  value: Joi.string().length(Joi.ref('length'), 'utf8').required()
});

Possible validation errors: string.length, string.ref

string.lowercase()

Requires the string value to be all lowercase. If the validation convert option is on (enabled by default), the string
will be forced to lowercase.

const schema = Joi.string().lowercase();

Possible validation errors: string.lowercase

string.max(limit, [encoding])

Specifies the maximum number of string characters where:

const schema = Joi.string().max(10);
const schema = Joi.object({
  max: Joi.string().required(),
  value: Joi.string().max(Joi.ref('max'), 'utf8').required()
});

Possible validation errors: string.max, string.ref

string.min(limit, [encoding])

Specifies the minimum number string characters where:

const schema = Joi.string().min(2);
const schema = Joi.object({
  min: Joi.string().required(),
  value: Joi.string().min(Joi.ref('min'), 'utf8').required()
});

Possible validation errors: string.min, string.ref

string.normalize([form])

Requires the string value to be in a Unicode normalized
form. If the validation convert option is on (enabled by default), the string will be normalized.

const schema = Joi.string().normalize(); // defaults to NFC
const schema = Joi.string().normalize('NFC'); // canonical composition
const schema = Joi.string().normalize('NFD'); // canonical decomposition
const schema = Joi.string().normalize('NFKC'); // compatibility composition
const schema = Joi.string().normalize('NFKD'); // compatibility decomposition

Possible validation errors: string.normalize

string.pattern(regex, [name | options]) - aliases: regex

Defines a pattern rule where:

const schema = Joi.string().pattern(/^[abc]+$/);

const inlineNamedSchema = Joi.string().pattern(/^[0-9]+$/, 'numbers');
inlineNamedSchema.validate('alpha'); // ValidationError: "value" with value "alpha" fails to match the numbers pattern

const namedSchema = Joi.string().pattern(/^[0-9]+$/, { name: 'numbers'});
namedSchema.validate('alpha'); // ValidationError: "value" with value "alpha" fails to match the numbers pattern

const invertedSchema = Joi.string().pattern(/^[a-z]+$/, { invert: true });
invertedSchema.validate('lowercase'); // ValidationError: "value" with value "lowercase" matches the inverted pattern: [a-z]

const invertedNamedSchema = Joi.string().pattern(/^[a-z]+$/, { name: 'alpha', invert: true });
invertedNamedSchema.validate('lowercase'); // ValidationError: "value" with value "lowercase" matches the inverted alpha pattern

Possible validation errors: string.pattern.base, string.pattern.invert.base, string.pattern.invert.name, string.pattern.name

string.replace(pattern, replacement)

Replace characters matching the given pattern with the specified
replacement string where:

const schema = Joi.string().replace(/b/gi, 'x');
await schema.validateAsync('abBc');  // return value will be 'axxc'

When pattern is a string all its occurrences will be replaced.

string.token()

Requires the string value to only contain a-z, A-Z, 0-9, and underscore _.

const schema = Joi.string().token();

Possible validation errors: string.token

string.trim([enabled])

Requires the string value to contain no whitespace before or after. If the validation convert option is on (enabled by
default), the string will be trimmed.

Parameters are:

const schema = Joi.string().trim();
const schema = Joi.string().trim(false); // disable trim flag

Possible validation errors: string.trim

string.truncate([enabled])

Specifies whether the string.max() limit should be used as a truncation.

Parameters are:

const schema = Joi.string().max(5).truncate();

string.uppercase()

Requires the string value to be all uppercase. If the validation convert option is on (enabled by default), the string
will be forced to uppercase.

const schema = Joi.string().uppercase();

Possible validation errors: string.uppercase

string.uri([options])

Requires the string value to be a valid RFC 3986 URI.

// Accept git or git http/https
const schema = Joi.string().uri({
  scheme: [
    'git',
    /git\+https?/
  ]
});

Possible validation errors: string.uri, string.uriCustomScheme, string.uriRelativeOnly, string.domain

symbol

Generates a schema object that matches a Symbol data type.

If the validation convert option is on (enabled by default), the mappings declared in map() will be tried for an eventual match.

Supports the same methods of the any() type.

const schema = Joi.symbol().map({ 'foo': Symbol('foo'), 'bar': Symbol('bar') });
await schema.validateAsync('foo');

Possible validation errors: symbol.base

symbol.map(map)

Allows values to be transformed into Symbols, where:

const schema = Joi.symbol().map([
    [1, Symbol('one')],
    ['two', Symbol('two')]
]);

Possible validation errors: symbol.map

Extensions

The extend() method adds custom types to joi. Extensions can be :

Full documentation is upcoming.

const Joi = require('@hapi/joi');

const custom = Joi.extend((joi) => {

    return {
        type: 'million',
        base: joi.number(),
        messages: {
            'million.base': '"{{#label}}" must be at least a million',
            'million.big': '"{{#label}}" must be at least five millions',
            'million.round': '"{{#label}}" must be a round number',
            'million.dividable': '"{{#label}}" must be dividable by {{#q}}'
        },
        coerce(value, helpers) {

            // Only called when prefs.convert is true

            if (helpers.schema.$_getRule('round')) {
                return { value: Math.round(value) };
            }
        },
        validate(value, helpers) {

            // Base validation regardless of the rules applied

            if (value < 1000000) {
                return { value, errors: helpers.error('million.base') };
            }

            // Check flags for global state

            if (schema.$_getFlag('big') &&
                value < 5000000) {

                return { value, errors: helpers.error('million.big') };
            }
        },
        rules: {
            big: {
                alias: 'large',
                method() {

                    return this.$_setFlag('big', true);
                }
            },
            round: {
                convert: true,              // Dual rule: converts or validates
                method() {

                    return this.$_addRule('round');
                },
                validate(value, helpers, args, options) {

                    // Only called when prefs.convert is false (due to rule convert option)

                    if (value % 1 !== 0) {
                        return helpers.error('million.round');
                    }
                }
            },
            dividable: {
                multi: true,                // Rule supports multiple invocations
                method(q) {

                    return this.$_addRule({ name: 'dividable', args: { q } });
                },
                args: [
                    {
                        name: 'q',
                        ref: true,
                        assert: (value) => typeof value === 'number' && !isNaN(value),
                        message: 'must be a number'
                    }
                ],
                validate(value, helpers, args, options) {

                    if (value % args.q === 0) {
                        return value;       // Value is valid
                    }

                    return helpers.error('million.dividable', { q: args.q });
                }
            },
            even: {
                method() {

                    // Rule with only method used to alias another rule

                    return this.dividable(2);
                }
            }
        }
    };
});

const schema = custom.object({
    a: custom.million().round().dividable(Joi.ref('b')),
    b: custom.number(),
    c: custom.million().even().dividable(7),
    d: custom.million().round().prefs({ convert: false }),
    e: custom.million().large()
});

Advanced functions

$_root

TODO

$_super

TODO

$_temp

TODO

$_terms

TODO

$_addRule(options)

TODO

$_compile(schema, options)

TODO

$_createError(code, value, local, state, prefs, options)

TODO

$_getFlag(name)

TODO

$_getRule(name)

TODO

$_mapLabels(path)

TODO

$_match(value, state, prefs, overrides)

TODO

$_modify(options)

TODO

$_mutateRebuild()

TODO

$_mutateRegister(schema, options)

TODO

$_property(name)

TODO

$_reach(path)

TODO

$_rootReferences()

TODO

$_setFlag(name, value, options)

TODO

$_validate(value, state, prefs)

TODO

Errors

ValidationError

joi throws or returns ValidationError objects containing :

List of errors

alternatives.all

The value did not match all of the alternative schemas.

alternatives.any

No alternative was found to test against the input due to try criteria.

alternatives.match

No alternative matched the input due to specific matching rules for at least one of the alternatives.

Additional local context properties:

{
    details: Array<object>, // An array of details for each error found while trying to match to each of the alternatives
    message: string // The combined error messages
}

alternatives.one

The value matched more than one alternative schema.

alternatives.types

The provided input did not match any of the allowed types.

Additional local context properties:

{
    types: Array<string> // The list of expected types
}

any.custom

A custom validation method threw an exception.

Additional local context properties:

{
    error: Error // The error thrown
}

any.default

If your any.default() generator function throws error, you will have it here.

Additional local context properties:

{
    error: Error // Error generated during the default value function call
}

any.failover

If your any.failover() generator function throws error, you will have it here.

Additional local context properties:

{
    error: Error // Error generated during the failover value function call
}

any.invalid

The value matched a value listed in the invalid values.

Additional local context properties:

{
    invalids: Array<any> // Contains the list of the invalid values that should be rejected
}

any.only

Only some values were allowed, the input didn't match any of them.

Additional local context properties:

{
    valids: Array<any> // Contains the list of the valid values that were expected
}

any.ref

A reference was used in rule argument and the value pointed to by that reference in the input is not valid.

Additional local context properties:

{
    arg: string, // The argument name
    reason: string, // The reason the referenced value is invalid
    ref: Reference // Reference used
}

any.required

A required value wasn't present.

any.unknown

A value was present while it wasn't expected.

array.base

The value is not of Array type or could not be cast to an Array from a string.

array.excludes

The array contains a value that is part of the exclusion list.

Additional local context properties:

{
    pos: number // Index where the value was found in the array
}

array.includesRequiredBoth

Some values were expected to be present in the array and are missing. This error happens when we have a mix of labeled and unlabeled schemas.

Additional local context properties:

{
    knownMisses: Array<string>, // Labels of all the missing values
    unknownMisees: number // Count of missing values that didn't have a label
}

array.includesRequiredKnowns

Some values were expected to be present in the array and are missing. This error happens when we only have labeled schemas.

Additional local context properties:

{
    knownMisses: Array<string> // Labels of all the missing values
}

array.includesRequiredUnknowns

Some values were expected to be present in the array and are missing. This error happens when we only have unlabeled schemas.

Additional local context properties:

{
    unknownMisees: number // Count of missing values that didn't have a label
}

array.includes

The value didn't match any of the allowed types for that array.

Additional local context properties:

{
    pos: number // Index where the value was found in the array
}

array.length

The array is not of the expected length.

Additional local context properties:

{
    limit: number // Length that was expected for this array
}

array.max

The array has more elements than the maximum allowed.

Additional local context properties:

{
    limit: number // Maximum length that was expected for this array
}

array.min

The array has less elements than the minimum allowed.

Additional local context properties:

{
    limit: number // Minimum length that was expected for this array
}

array.orderedLength

Given an array.ordered(), that array has more elements than it should.

Additional local context properties:

{
    pos: number, // Index where the value was found in the array
    limit: number // Maximum length that was expected for this array
}

array.sort

The array did not match the required sort order.

Additional local context properties:

{
    order: string, // 'ascending' or 'descending'
    by: string // The object key used for comparison
}

array.sort.mismatching

Failed sorting the array due to mismatching item types.

array.sort.unsupported

Failed sorting the array due to unsupported item types.

Additional local context properties:

{
    type: string // The unsupported array item type
}

array.sparse

An undefined value was found in an array that shouldn't be sparse.

Additional local context properties:

{
    pos: number // Index where an undefined value was found in the array
}

array.unique

A duplicate value was found in an array.

Additional local context properties:

{
    pos: number, // Index where the duplicate value was found in the array
    dupePos: number, // Index where the first appearance of the duplicate value was found in the array
    dupeValue: any // Value with which the duplicate was met
}

array.hasKnown

The schema on an array.has() was not found in the array. This error happens when the schema is labeled.

Additional local context properties:

{
    patternLabel: string // Label of assertion schema
}

array.hasUnknown

The schema on an array.has() was not found in the array. This error happens when the schema is unlabeled.

binary.base

The value is either not a Buffer or could not be cast to a Buffer from a string.

binary.length

The buffer was not of the specified length.

Additional local context properties:

{
    limit: number // Length that was expected for this buffer
}

binary.max

The buffer contains more bytes than expected.

Additional local context properties:

{
    limit: number // Maximum length that was expected for this buffer
}

binary.min

The buffer contains less bytes than expected.

Additional local context properties:

{
    limit: number // Minimum length that was expected for this buffer
}

boolean.base

The value is either not a boolean or could not be cast to a boolean from one of the truthy or falsy values.

date.base

The value is either not a date or could not be cast to a date from a string or a number.

date.format

The date does not match the required format.

Additional local context properties:

{
    format: string // The required format
}

date.greater

The date is over the limit that you set.

Additional local context properties:

{
    limit: Date // Maximum date
}

date.less

The date is under the limit that you set.

Additional local context properties:

{
    limit: Date // Minimum date
}

date.max

The date is over or equal to the limit that you set.

Additional local context properties:

{
    limit: Date // Maximum date
}

date.min

The date is under or equal to the limit that you set.

Additional local context properties:

{
    limit: Date // Minimum date
}

date.strict

Occurs when the input is not a Date type and convert is disabled.

function.arity

The number of arguments for the function doesn't match the required number.

Additional local context properties:

{
    n: number // Expected arity
}

function.class

The input is not a JavaScript class.

function.maxArity

The number of arguments for the function is over the required number.

Additional local context properties:

{
    n: number // Maximum expected arity
}

function.minArity

The number of arguments for the function is under the required number.

Additional local context properties:

{
    n: number // Minimum expected arity
}

number.base

The value is not a number or could not be cast to a number.

number.greater

The number is lower or equal to the limit that you set.

Additional local context properties:

{
    limit: number // Minimum value that was expected for this number
}

number.infinity

The number is Infinity or -Infinity.

number.integer

The number is not a valid integer.

number.less

The number is higher or equal to the limit that you set.

Additional local context properties:

{
    limit: number // Maximum value that was expected for this number
}

number.max

The number is higher than the limit that you set.

Additional local context properties:

{
    limit: number // Maximum value that was expected for this number
}

number.min

The number is lower than the limit that you set.

Additional local context properties:

{
    limit: number // Minimum value that was expected for this number
}

number.multiple

The number could not be divided by the multiple you provided.

Additional local context properties:

{
    multiple: number // The number of which the input is supposed to be a multiple of
}

number.negative

The number was positive.

number.port

The number didn't look like a port number.

number.positive

The number was negative.

number.precision

The number didn't have the required precision.

Additional local context properties:

{
    limit: number // The precision that it should have had
}

number.unsafe

The number is not within the safe range of JavaScript numbers.

object.unknown

An unexpected property was found in the object.

Additional local context properties:

{
    child: string // Property that is unexpected
}

object.and

The AND condition between the properties you specified was not satisfied in that object.

Additional local context properties:

{
    present: Array<string>, // List of properties that are set
    presentWithLabels: Array<string>, // List of labels for the properties that are set
    missing: Array<string>, // List of properties that are not set
    missingWithLabels: Array<string> // List of labels for the properties that are not set
}

object.assert

The schema on an object.assert() failed to validate.

Additional local context properties:

{
    subject: object, // The assertion subject. When it is a reference, use subject.key for the display path.
    message: string // Custom message when provided
}

object.base

The value is not of the expected type.

Additional local context properties:

{
    type: string // The expected type
}

object.length

The number of keys for this object is not of the expected length.

Additional local context properties:

{
    limit: number // Number of keys that was expected for this object
}

object.max

The number of keys for this object is over or equal to the limit that you set.

Additional local context properties:

{
    limit: number // Maximum number of keys
}

object.min

The number of keys for this object is under or equal to the limit that you set.

Additional local context properties:

{
    limit: number // Minimum number of keys
}

object.missing

The OR or XOR condition between the properties you specified was not satisfied in that object, none of it were set.

Additional local context properties:

{
    peers: Array<string>, // List of properties were none of it was set
    peersWithLabels: Array<string> // List of labels for the properties were none of it was set
}

object.nand

The NAND condition between the properties you specified was not satisfied in that object.

Additional local context properties:

{
    main: string, // One of the properties that was present
    mainWithLabel: string, // The label of the `main` property
    peers: Array<string>, // List of the other properties that were present
    peersWithLabels: Array<string> // List of the labels of the other properties that were present
}

object.pattern.match

The object keys failed to match a pattern's matches requirement.

Additional local context properties:

{
    details: Array<object>, // An array of details for each error found while trying to match to each of the alternatives
    message: string, // The combined error messages
    matches: Array<string>  // The matching keys
}

object.refType

The object is not a Joi.ref().

object.rename.multiple

Another rename was already done to the same target property.

Additional local context properties:

{
    from: string, // Origin property name of the rename
    to: string, // Target property of the rename
    pattern: boolean // Indicates if the rename source was a pattern (regular expression)
}

object.rename.override

The target property already exists and you disallowed overrides.

Additional local context properties:

{
    from: string, // Origin property name of the rename
    to: string, // Target property of the rename
    pattern: boolean // Indicates if the rename source was a pattern (regular expression)
}

object.schema

The object was not a joi schema.

Additional local context properties:

{
    type: string // The required schema
}

object.instance

The object is not of the type you specified.

Additional local context properties:

{
    type: string // Type name the object should have been
}

object.with

Property that should have been present at the same time as another one was missing.

Additional local context properties:

{
    main: string, // Property that triggered the check
    mainWithLabel: string, // Label of the property that triggered the check
    peer: string, // Property that was missing
    peerWithLabels: string // Label of the other property that was missing
}

object.without

Property that should have been absent at the same time as another one was present.

Additional local context properties:

{
    main: string, // Property that triggered the check
    mainWithLabel: string, // Label of the property that triggered the check
    peer: string, // Property that was present
    peerWithLabels: string // Label of the other property that was present
}

object.xor

The XOR condition between the properties you specified was not satisfied in that object.

Additional local context properties:

{
    peers: Array<string>, // List of properties where none of it or too many of it was set
    peersWithLabels: Array<string> // List of labels for the properties where none of it or too many of it was set
}

object.oxor

The optional XOR condition between the properties you specified was not satisfied in that object.

Additional local context properties:

{
    peers: Array<string>, // List of properties where too many of it was set
    peersWithLabels: Array<string> // List of labels for the properties where too many of it was set
}

string.alphanum

The string doesn't only contain alphanumeric characters.

string.base64

The string isn't a valid base64 string.

string.base

The input is not a string.

string.creditCard

The string is not a valid credit card number.

string.dataUri

The string is not a valid data URI.

string.domain

The string is not a valid domain name.

string.email

The string is not a valid e-mail.

Additional local context properties:

{
    invalids: [string] // Array of invalid emails
}

string.empty

When an empty string is found and denied by invalid values.

string.guid

The string is not a valid GUID.

string.hexAlign

The string contains hexadecimal characters but they are not byte-aligned.

string.hex

The string is not a valid hexadecimal string.

string.hostname

The string is not a valid hostname.

string.ipVersion

The string is not a valid IP address considering the provided constraints.

Additional local context properties:

{
    cidr: string, // CIDR used for the validation
    version: Array<string> // List of IP version accepted
}

string.ip

The string is not a valid IP address.

Additional local context properties:

{
    cidr: string // CIDR used for the validation
}

string.isoDate

The string is not a valid ISO date string.

string.isoDuration

The string must be a valid ISO 8601 duration.

string.length

The string is not of the expected length.

Additional local context properties:

{
    limit: number, // Length that was expected for this string
    encoding: undefined | string // Encoding specified for the check if any
}

string.lowercase

The string isn't all lower-cased.

string.max

The string is larger than expected.

Additional local context properties:

{
    limit: number, // Maximum length that was expected for this string
    encoding: undefined | string // Encoding specified for the check if any
}

string.min

The string is smaller than expected.

Additional local context properties:

{
    limit: number, // Minimum length that was expected for this string
    encoding: undefined | string // Encoding specified for the check if any
}

string.normalize

The string isn't valid in regards of the normalization form expected.

Additional local context properties:

{
    form: string // Normalization form that is expected
}

string.pattern.base

The string didn't match the regular expression.

Additional local context properties:

{
    name: undefined, // Undefined since the regular expression has no name
    pattern: string // Regular expression
}

string.pattern.name

The string didn't match the named regular expression.

Additional local context properties:

{
    name: string, // Name of the regular expression
    pattern: string // Regular expression
}

string.pattern.invert.base

The string matched the regular expression while it shouldn't.

Additional local context properties:

{
    name: undefined, // Undefined since the regular expression has no name
    pattern: string // Regular expression
}

string.pattern.invert.name

The string matched the named regular expression while it shouldn't.

Additional local context properties:

{
    name: string, // Name of the regular expression
    pattern: string // Regular expression
}

string.token

The string isn't a token.

string.trim

The string contains whitespace around it.

string.uppercase

The string isn't all upper-cased.

string.uri

The string isn't a valid URI.

string.uriCustomScheme

The string isn't a valid URI considering the custom schemes.

Additional local context properties:

{
    scheme: string // Scheme prefix that is expected in the URI
}

string.uriRelativeOnly

The string is a valid relative URI.

symbol.base

The input is not a Symbol.

symbol.map

The input is not a Symbol or could not be converted to one.