Skip to content

Instantly share code, notes, and snippets.

@danharper
Last active August 29, 2015 14:26
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save danharper/6902b69943a7cbcfe66f to your computer and use it in GitHub Desktop.
Save danharper/6902b69943a7cbcfe66f to your computer and use it in GitHub Desktop.
Validation Library

To define your validation rules, provide a Map. Keys are field names, values are either a validation rule, or an array of validation rules.

// one rule
const rules = new Map([
  ['name', required]
])

// multiple rules
const rules = new Map([
  ['name', [required, longerThanChars(1)]]
])

Validation rules are functions which are given three arguments:

  • value - the value of the field being validated
  • field - the name of the field being validated
  • fields - an object of all fields, so you can build cross-field validations

The following validation rules are currently provided:

  • required - asserts the field is not null/undefined
  • mustBe(expected) - asserts the field matches expected
  • eq(expected) - alias of mustBe
  • oneOf(expectations) - asserts the field is one of the expectations (array)
  • shorterThanChars(expectedMaxChars) - asserts the field is shorter than expectedMaxChars
  • longerThanChars(expectedMinChars) - asserts the field is longer than expectedMinChars

As you can see, some validations are simple functions, others are function factories which allow you to pass through expectations.

We could write a custom rule to assert the field "starts with **":

// es6
const startsWithStars = value => assert(value.startsWith('**'), 'Must start with "**"')

// es5
function startsWithStars(value) {
  return assert(value.indexOf('**') === 0, 'Must start with "**"')
}

Or, we could write a generic "starts with" rule:

// es6
const startsWith = expected => value => assert(value.startsWith(expected), `Must start with "${expected}"`)

// es5
function startsWith(expected) {
  return function(value) {
    return assert(value.indexOf(expected) === 0, 'Must start with "' + expected + '"')
  }
}

Usage:

const rules = new Map([
  ['name', [startsWithStars, startsWith('**')]] // both rules assert the same thing
])

The validation system is flexible enough to provide cross-field validation rules. For example, you may want to assert that parent is required only if age is less than 18. We can use the onlyIf rule, like so:

const rules = new Map([
  ['parent', [
    onlyIf('age', lessThan(18), required)
  ]]
])

onlyIf is a more complex function factory which is provided for you.

By default, each rule provides a generic error message when it fails, e.g. Field is required or Must be less than "18" etc.

You can provide custom error messages for each rule by specifying it as a two-field array:

const rules = new Map([
  ['name', [
    [required, "You can't be anonymous, sorry!"]
  ]],
  ['age', [
    [greaterThan(18), "You must be at least 18"]
  ]]
])

The message can be provided as a string, or if you want more control over the message, you can provide it as a function which will be given two arguments:

  • value - the value of the field being validated
  • field - the name of the field being validated

So you could:

const rules = new Map([
  ['age', [
    [greaterThan(18), value => `Sorry you can't be ${value}, you must be at least 18.`]
  ]]
])

Which if you provided age as 17, would provide the error message "Sorry, you can't be 17, you must be at least 18.".

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment