Home

Awesome

Verily

Map validation library for Clojure and ClojureScript

Why

Most other validation libraries (such as valip) assume validation is done per key, rather than on a map as a whole. This makes it difficult to write multi-key validations. Validation functions in Verily take an entire map, making multi-key (or single-key) validations easy.

Verily also provides a declarative, data-oriented API in addition to a conventional, function-oriented API. Using data to describe validations has benefits in certain use cases. For instance, you can share validation specifications between Clojure and ClojureScript.

Installation

Leiningen:

[jkkramer/verily "0.6.0"]

Usage

(ns example.core
  (:require [jkkramer.verily :as v]))

There are two ways to validate a map:

  1. With a validation specification - i.e., data, which Verily turns into a validation function for you
  2. With a validation function

To validate using a validation specification:

(def validations
  [[:required [:foo :bar :password]]
   [:equal [:password :confirm-password] "Passwords don't match, dummy"]
   [:min-length 8 :password]])

(v/validate {:foo "foo"
             :password "foobarbaz"
             :password-confirm "foobarba"}
            validations)
;; Returns:
({:keys (:bar), :msg "must not be blank"}
 {:keys [:password :confirm-password], :msg "Passwords don't match, dummy"})

To turn a validation specification into a function yourself:

(def validator (v/validations->fn validations))

You can use validation functions instead of data if you prefer. This makes it easier to write your own:

;; Custom validator
(defn validate-password [m]
  (when (#{"12345" "password" "hunter2"} (:password m))
    {:keys [:password] :msg "You can't use that password"}))

;; Combine several built-in validators and our own custom one
(def validator
  (v/combine
    (v/required [:foo :bar :password])
    (v/equal [:password :password-confirm])
    (v/min-length 8 :password)
    validate-password))

(validator {:foo "foo"
            :password "foobarbaz"
            :password-confirm "foobarba"})
;; Returns:
({:keys (:bar), :msg "must not be blank"}
 {:keys [:password :password-confirm], :msg "must be equal"})

Validation Function Contract

The contract for a validation function is:

Built-in Validations

All validation specifications accept a key or sequence of keys. The message is always optional.

Keys can be dotted keywords such as :foo.bar, which will be interpreted as a nested path (if the :foo.bar key does not exist in the top-level map). Strings such as "foo[bar]" are also allowed, and have the same semantics.

Unless :required is used, all validations allow the keys to be absent from the map, or have a nil value (or blank if a string-based type).

All validation specifications have corresponding validator functions in the jkkramer.verily namespace, if you prefer to use those directly.

License

Copyright © 2012-2013 Justin Kramer

Distributed under the Eclipse Public License, the same as Clojure.