joi-async
TypeScript icon, indicating that this package has built-in type declarations

0.0.7 • Public • Published

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: 'someone@example.com',
    });    
  } 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 to true. 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 to customAsync.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
  }
})();

Readme

Keywords

none

Package Sidebar

Install

npm i joi-async

Weekly Downloads

3

Version

0.0.7

License

ISC

Unpacked Size

14.3 kB

Total Files

9

Last publish

Collaborators

  • dlitsman