joi-async
v0.0.7
Published
# DO NOT USE YET!
Downloads
3
Readme
joi-async
DO NOT USE YET!
Async validation support for Joi. Adds mixins to Joi object to allow custom async validation callbacks.
Usage
import 'joi-async'
import Joi from 'joi';
// or you can use
// import Joi from 'joi-async';
// ... or via require()
// require('joi-async');
// const Joi = require('joi');
const checkUsernameIsUnique = (value, state, options) => {
return new Promise((resolve, reject) => {
setTimeout(() => {
// same error message keys as in Joi
value === 'taken' ? reject('!!The username "{{!value}}" has already been taken') : resolve();
}, 500);
});
};
(async () => {
const schema = Joi.object().keys({
username: Joi.string().alphanum().required().async(checkUsernameIsUnique),
password: Joi.string().regex(/^[a-zA-Z0-9]{3,30}$/),
email: Joi.string().email({ minDomainAtoms: 2 })
});
try {
const filteredValues = await schema.asyncValidate({
username: 'taken',
password: '123456',
email: '[email protected]',
});
} catch (e) {
console.log(e.details);
/*
[
{
"message": "The username \"taken\" has already been taken",
"path": [
"username"
],
"type": "customAsync.error",
"context": {
"value": "taken",
"key": "username",
"label": "username"
}
}
]
*/
}
})();
Methods
any.async(callback)
callback
- callback function can be synchronous or Promise-based
Joi.asyncValidate(value, schema, [options], [callback])
Same rules as Joi.validate() but with extra options
any.validate(value, [options], [callback])
Same rules as any.validate() but with extra options
Options
afterSyncSuccess
: defaults totrue
. All callbacks will be called only after regular synchronous flow is successful.
Callbacks
Callbacks can return Promise or be synchronous. A callback receives the following arguments:
value
- the value being processed by Joi.state
- an object containing the current context of validation.key
- the key of the current value.path
- the full path of the current value.parent
- the potential parent of the current value.
options
- options object provided through any().options() or Joi.validate().
If callback returns a value it will transform original value in the output in case if
{ convert: true }
is used.
Errors
You can use Promise.reject('error template')
or throw 'error template'
.
However, if you need full control over resulting error details you can use JoiAsyncError
to override errorCode
as well
JoiAsyncError(message[, errorCode])
message
- error message template, same rules as regular Joi error messages. (e.g.!!Example error message label: {{label}}, value: {{!value}}
)errorCode
- defaults tocustomAsync.error
import JoiAsyncError from 'joi-async/error';
import Joi from 'joi';
const checkUsernameIsUnique = (value) => {
throw new JoiAsyncError('!!taken', 'error.taken');
};
(async () => {
const schema = Joi.object().keys({
username: Joi.string().required().async(checkUsernameIsUnique),
});
try {
await schema.asyncValidate({
username: 'taken',
});
} catch (e) {
console.log(e.details);
/*
[
{
"message": "taken",
"path": [
"username"
],
"type": "error.taken", // new code
"context": {
"value": "taken",
"key": "username",
"label": "username"
}
}
]
*/
}
})();
Examples
Async with overriding
import 'joi-async'
import Joi from 'joi';
const removeBadWords = async (value) => {
const withoutBadWords = await thirdPartyServiceToRemoveBadWords(value);
// Will replace original value if {convert: true} option
return withoutBadWords;
};
(async () => {
const schema = Joi.object().keys({
title: Joi.string().required().async(removeBadWords),
});
try {
const filteredValues = await schema.asyncValidate({
username: 'example',
});
} catch (e) {
// standard Joi error object
}
})();
Full example
import 'joi-async'
import Joi from 'joi';
const checkUsername = async (value) => {
const available = await checkDatabaseUsernameAvailbale(value);
if (!available) {
throw '!!This username has already been taken';
}
// No need to return anything if you don't want to override it
};
(async () => {
const schema = Joi.object().keys({
title: Joi.string().required().async(checkUsername),
});
try {
const filteredValues = await schema.asyncValidate({
username: 'example',
});
} catch (e) {
// standard Joi error object
}
})();
Synchronous example
import 'joi-async'
import Joi from 'joi';
import _ from 'lodash';
const kebabify = (value) => {
// works only with { convert: true }
return _.kebabCase(value);
};
(async () => {
const schema = Joi.object().keys({
title: Joi.string().required().async(kebabify),
});
try {
const filteredValues = await schema.asyncValidate({
key: 'Example Message',
});
console.log(filteredValues.key); // example-message
} catch (e) {
// standard Joi error object
}
})();