schema.core

A library for data shape definition and validation. A Schema is just Clojure data,
which can be used to document and validate Clojure functions and data.

For example,

(def FooBar {:foo Keyword :bar [Number]}) ;; a schema

(check FooBar {:foo :k :bar [1.0 2.0 3.0]})
==> nil

representing successful validation, but the following all return helpful errors
describing how the provided data fails to measure up to schema FooBar's standards.

(check FooBar {:bar [1.0 2.0 3.0]})
==> {:foo missing-required-key}

(check FooBar {:foo 1 :bar [1.0 2.0 3.0]})
==> {:foo (not (keyword? 1))}

(check FooBar {:foo :k :bar [1.0 2.0 3.0] :baz 1})
==> {:baz disallowed-key}

Schema lets you describe your leaf values using the Any, Keyword, Symbol, Number,
String, and Int definitions below, or (in Clojure) you can use arbitrary Java
classes or primitive casts to describe simple values.

From there, you can build up schemas for complex types using Clojure syntax
(map literals for maps, set literals for sets, vector literals for sequences,
with details described below), plus helpers below that provide optional values,
enumerations, arbitrary predicates, and more.

Assuming you (:require [schema.core :as s :include-macros true]),
Schema also provides macros for defining records with schematized elements
(s/defrecord), and named or anonymous functions (s/fn and s/defn) with
schematized inputs and return values.  In addition to producing better-documented
records and functions, these macros allow you to retrieve the schema associated
with the defined record or function.  Moreover, functions include optional
*validation*, which will throw an error if the inputs or outputs do not
match the provided schemas:

(s/defrecord FooBar
 [foo :- Int
  bar :- String])

(s/defn quux :- Int
 [foobar :- Foobar
  mogrifier :- Number]
 (* mogrifier (+ (:foo foobar) (Long/parseLong (:bar foobar)))))

(quux (FooBar. 10 "5") 2)
==> 30

(fn-schema quux)
==> (=> Int (record user.FooBar {:foo Int, :bar java.lang.String}) java.lang.Number)

(s/with-fn-validation (quux (FooBar. 10.2 "5") 2))
==> Input to quux does not match schema: [(named {:foo (not (integer? 10.2))} foobar) nil]

As you can see, the preferred syntax for providing type hints to schema's defrecord,
fn, and defn macros is to follow each element, argument, or function name with a
:- schema.  Symbols without schemas default to a schema of Any.  In Clojure,
class (e.g., clojure.lang.String) and primitive schemas (long, double) are also
propagated to tag metadata to ensure you get the type hinting and primitive
behavior you ask for.

If you don't like this style, standard Clojure-style typehints are also supported:

(fn-schema (s/fn [^String x]))
==> (=> Any java.lang.String)

You can directly type hint a symbol as a class, primitive, or simple
schema.

See the docstrings of defrecord, fn, and defn for more details about how
to use these macros.

->AnythingSchema

(->AnythingSchema _)
Positional factory function for class schema.core.AnythingSchema.

->Both

(->Both schemas)
Positional factory function for class schema.core.Both.

->ConditionalSchema

(->ConditionalSchema preds-and-schemas error-symbol)
Positional factory function for class schema.core.ConditionalSchema.

->CondPre

(->CondPre schemas)
Positional factory function for class schema.core.CondPre.

->Either

(->Either schemas)
Positional factory function for class schema.core.Either.

->EnumSchema

(->EnumSchema vs)
Positional factory function for class schema.core.EnumSchema.

->EqSchema

(->EqSchema v)
Positional factory function for class schema.core.EqSchema.

->FnSchema

(->FnSchema output-schema input-schemas)
Positional factory function for class schema.core.FnSchema.

->Isa

(->Isa h parent)
Positional factory function for class schema.core.Isa.

->MapEntry

(->MapEntry key-schema val-schema)
Positional factory function for class schema.core.MapEntry.

->Maybe

(->Maybe schema)
Positional factory function for class schema.core.Maybe.

->NamedSchema

(->NamedSchema schema name)
Positional factory function for class schema.core.NamedSchema.

->One

(->One schema optional? name)
Positional factory function for class schema.core.One.

->OptionalKey

(->OptionalKey k)
Positional factory function for class schema.core.OptionalKey.

->Predicate

(->Predicate p? pred-name)
Positional factory function for class schema.core.Predicate.

->Protocol

(->Protocol p)
Positional factory function for class schema.core.Protocol.

->Queue

(->Queue schema)
Positional factory function for class schema.core.Queue.

->Record

(->Record klass schema)
Positional factory function for class schema.core.Record.

->Recursive

(->Recursive derefable)
Positional factory function for class schema.core.Recursive.

->RequiredKey

(->RequiredKey k)
Positional factory function for class schema.core.RequiredKey.

=>

macro

(=> output-schema & arg-schemas)
Convenience macro for defining function schemas with a single arity; like =>*, but
there is no vector around the argument schemas for this arity.

=>*

macro

(=>* output-schema & arity-schema-specs)
Produce a function schema from an output schema and a list of arity input schema specs,
each of which is a vector of argument schemas, ending with an optional '& more-schema'
specification where more-schema must be a sequence schema.

Currently function schemas are purely descriptive; there is no validation except for
functions defined directly by s/fn or s/defn

Any

Any value, including nil.

as-queue

(as-queue col)

Bool

Boolean true or false

both

deprecated in 1.0.0

(both & schemas)
A value that must satisfy every schema in schemas.

DEPRECATED: prefer 'conditional' with a single condition
instead.

When used with coercion, coerces each schema in sequence.

check

(check schema x)
Return nil if x matches schema; otherwise, returns a value that looks like the
'bad' parts of x with ValidationErrors at the leaves describing the failures.

If you will be checking many datums, it is much more efficient to create
a 'checker' once and call it on each of them.

checker

(checker schema)
Compile an efficient checker for schema, which returns nil for valid values and
error descriptions otherwise.

clj-1195-fixed?

CLJ1195Check

protocol

members

dummy-method

(dummy-method this)

cond-pre

(cond-pre & schemas)
A replacement for `either` that constructs a conditional schema
based on the schema spec preconditions of the component schemas.

EXPERIMENTAL

conditional

(conditional & preds-and-schemas)
Define a conditional schema.  Takes args like cond,
(conditional pred1 schema1 pred2 schema2 ...),
and checks the first schema where pred is true on the value.
Unlike cond, throws if the value does not match any condition.
:else may be used as a final condition in the place of (constantly true).
More efficient than either, since only one schema must be checked.
An optional final argument can be passed, a symbol to appear in
error messages when none of the conditions match.

def

macro

(def & def-args)
Like def, but takes a schema on the var name (with the same format
as the output schema of s/defn), requires an initial value, and
asserts that the initial value matches the schema on the var name
(regardless of the status of with-fn-validation).  Due to
limitations of add-watch!, cannot enforce validation of subsequent
rebindings of var.  Throws at compile-time for clj, and client-side
load-time for cljs.

Example:

(s/def foo :- long "a long" 2)

defmethod

macro

(defmethod multifn dispatch-val & fn-tail)
Like clojure.core/defmethod, except that schema-style typehints can be given on
the argument symbols and after the dispatch-val (for the return value).

See (doc s/defn) for details.

Examples:

  (s/defmethod mymultifun :a-dispatch-value :- s/Num [x :- s/Int y :- s/Num] (* x y))

  ;; You can also use meta tags like ^:always-validate by placing them
  ;; before the multifunction name:

  (s/defmethod ^:always-validate mymultifun :a-dispatch-value [x y] (* x y))

defn

macro

(defn & defn-args)
Like clojure.core/defn, except that schema-style typehints can be given on
the argument symbols and on the function name (for the return value).

You can call s/fn-schema on the defined function to get its schema back, or
use with-fn-validation to enable runtime checking of function inputs and
outputs.

(s/defn foo :- s/Num
 [x :- s/Int
  y :- s/Num]
 (* x y))

(s/fn-schema foo)
==> (=> java.lang.Number Int java.lang.Number)

(s/with-fn-validation (foo 1 2))
==> 2

(s/with-fn-validation (foo 1.5 2))
==> Input to foo does not match schema: [(named (not (integer? 1.5)) x) nil]

See (doc schema.core) for details of the :- syntax for arguments and return
schemas.

The overhead for checking if run-time validation should be used is very
small -- about 5% of a very small fn call.  On top of that, actual
validation costs what it costs.

You can also turn on validation unconditionally for this fn only by
putting ^:always-validate metadata on the fn name.

Gotchas and limitations:
 - The output schema always goes on the fn name, not the arg vector. This
   means that all arities must share the same output schema. Schema will
   automatically propagate primitive hints to the arg vector and class hints
   to the fn name, so that you get the behavior you expect from Clojure.
 - Schema metadata is only processed on top-level arguments.  I.e., you can
   use destructuring, but you must put schema metadata on the top-level
   arguments, not the destructured variables.

   Bad:  (s/defn foo [{:keys [x :- s/Int]}])
   Good: (s/defn foo [{:keys [x]} :- {:x s/Int}])
 - Only a specific subset of rest-arg destructuring is supported:
   - & rest works as expected
   - & [a b] works, with schemas for individual elements parsed out of the binding,
     or an overall schema on the vector
   - & {} is not supported.
 - Unlike clojure.core/defn, a final attr-map on multi-arity functions
   is not supported.

defrecord

macro

(defrecord name field-schema extra-key-schema? extra-validator-fn? & opts+specs)
Define a record with a schema.

In addition to the ordinary behavior of defrecord, this macro produces a schema
for the Record, which will automatically be used when validating instances of
the Record class:

(m/defrecord FooBar
 [foo :- Int
  bar :- String])

(schema.utils/class-schema FooBar)
==> (record user.FooBar {:foo Int, :bar java.lang.String})

(s/check FooBar (FooBar. 1.2 :not-a-string))
==> {:foo (not (integer? 1.2)), :bar (not (instance? java.lang.String :not-a-string))}

See (doc schema.core) for details of the :- syntax for record elements.

Moreover, optional arguments extra-key-schema? and extra-validator-fn? can be
passed to augment the record schema.
 - extra-key-schema is a map schema that defines validation for additional
   key-value pairs not in the record base (the default is to not allow extra
    mappings).
 - extra-validator-fn? is an additional predicate that will be used as part
   of validating the record value.

The remaining opts+specs (i.e., protocol and interface implementations) are
passed through directly to defrecord.

Finally, this macro replaces Clojure's map->name constructor with one that is
more than an order of magnitude faster (as of Clojure 1.5), and provides a
new strict-map->name constructor that throws or drops extra keys not in the
record base.

defrecord+

macro

(defrecord+ name field-schema extra-key-schema? extra-validator-fn? & opts+specs)
DEPRECATED -- canonical version moved to schema.potemkin
Like defrecord, but emits a record using potemkin/defrecord+.  You must provide
your own dependency on potemkin to use this.

defschema

macro

(defschema name form)(defschema name docstring form)
Convenience macro to make it clear to reader that body is meant to be used as a schema.
The name of the schema is recorded in the metadata.

either

deprecated in 1.0.0

(either & schemas)
A value that must satisfy at least one schema in schemas.
Note that `either` does not work properly with coercion

DEPRECATED: prefer `cond-pre`

WARNING: either does not work with coercion.  It is also slow and gives
bad error messages.  Please consider using `conditional` and friends
instead; they are more efficient, provide better error messages,
and work with coercion.

enum

(enum & vs)
A value that must be = to some element of vs.

eq

(eq v)
A value that must be (= v).

explain-input-schema

(explain-input-schema input-schema)

explicit-schema-key

(explicit-schema-key ks)

extend-primitive

macro

(extend-primitive cast-sym class-sym)

find-extra-keys-schema

(find-extra-keys-schema map-schema)

fn

macro

(fn & fn-args)
s/fn : s/defn :: clojure.core/fn : clojure.core/defn

See (doc s/defn) for details.

Additional gotchas and limitations:
 - Like s/defn, the output schema must go on the fn name. If you
   don't supply a name, schema will gensym one for you and attach
   the schema.
 - Unlike s/defn, the function schema is stored in metadata on the
   fn.  Clojure's implementation for metadata on fns currently
   produces a wrapper fn, which will decrease performance and
   negate the benefits of primitive type hints compared to
   clojure.core/fn.

fn-schema

(fn-schema f)
Produce the schema for a function defined with s/fn or s/defn.

fn-validation?

(fn-validation?)
Get the current global schema validation setting.

HasPrecondition

protocol

members

precondition

(precondition this)
Return a predicate representing the Precondition for this schema:
the predicate returns true if the precondition is satisfied.
(See spec.core for more details)

if

(if pred if-schema else-schema)
if the predicate returns truthy, use the if-schema, otherwise use the else-schema

Inst

The local representation of #inst ...

instance-precondition

(instance-precondition s klass)

Int

Any integral number

isa

(isa parent)(isa h parent)
A value that must be a child of parent.

Keyword

A keyword

letfn

macro

(letfn fnspecs & body)
s/letfn : s/fn :: clojure.core/letfn : clojure.core/fn

make-fn-schema

(make-fn-schema output-schema input-schemas)
A function outputting a value in output schema, whose argument vector must match one of
input-schemas, each of which should be a sequence schema.
Currently function schemas are purely descriptive; they validate against any function,
regardless of actual input and output types.

map->AnythingSchema

(map->AnythingSchema m__6289__auto__)
Factory function for class schema.core.AnythingSchema, taking a map of keywords to field values.

map->Both

(map->Both m__6289__auto__)
Factory function for class schema.core.Both, taking a map of keywords to field values.

map->ConditionalSchema

(map->ConditionalSchema m__6289__auto__)
Factory function for class schema.core.ConditionalSchema, taking a map of keywords to field values.

map->CondPre

(map->CondPre m__6289__auto__)
Factory function for class schema.core.CondPre, taking a map of keywords to field values.

map->Either

(map->Either m__6289__auto__)
Factory function for class schema.core.Either, taking a map of keywords to field values.

map->EnumSchema

(map->EnumSchema m__6289__auto__)
Factory function for class schema.core.EnumSchema, taking a map of keywords to field values.

map->EqSchema

(map->EqSchema m__6289__auto__)
Factory function for class schema.core.EqSchema, taking a map of keywords to field values.

map->FnSchema

(map->FnSchema m__6289__auto__)
Factory function for class schema.core.FnSchema, taking a map of keywords to field values.

map->Isa

(map->Isa m__6289__auto__)
Factory function for class schema.core.Isa, taking a map of keywords to field values.

map->MapEntry

(map->MapEntry m__6289__auto__)
Factory function for class schema.core.MapEntry, taking a map of keywords to field values.

map->Maybe

(map->Maybe m__6289__auto__)
Factory function for class schema.core.Maybe, taking a map of keywords to field values.

map->NamedSchema

(map->NamedSchema m__6289__auto__)
Factory function for class schema.core.NamedSchema, taking a map of keywords to field values.

map->One

(map->One m__6289__auto__)
Factory function for class schema.core.One, taking a map of keywords to field values.

map->OptionalKey

(map->OptionalKey m__6289__auto__)
Factory function for class schema.core.OptionalKey, taking a map of keywords to field values.

map->Predicate

(map->Predicate m__6289__auto__)
Factory function for class schema.core.Predicate, taking a map of keywords to field values.

map->Protocol

(map->Protocol m__6289__auto__)
Factory function for class schema.core.Protocol, taking a map of keywords to field values.

map->Queue

(map->Queue m__6289__auto__)
Factory function for class schema.core.Queue, taking a map of keywords to field values.

map->Record

(map->Record m__6289__auto__)
Factory function for class schema.core.Record, taking a map of keywords to field values.

map->Recursive

(map->Recursive m__6289__auto__)
Factory function for class schema.core.Recursive, taking a map of keywords to field values.

map->RequiredKey

(map->RequiredKey m__6289__auto__)
Factory function for class schema.core.RequiredKey, taking a map of keywords to field values.

map-entry

(map-entry key-schema val-schema)

maybe

(maybe schema)
A value that must either be nil or satisfy schema

named

(named schema name)
A value that must satisfy schema, and has a name for documentation purposes.

Num

Any number

one

(one schema name)
A single required element of a sequence (not repeated, the implicit default)

optional

(optional schema name)
A single optional element of a sequence (not repeated, the implicit default)

optional-key

(optional-key k)
An optional key in a map

optional-key?

(optional-key? ks)

pair

(pair first-schema first-name second-schema second-name)
A schema for a pair of schemas and their names

parse-sequence-schema

(parse-sequence-schema s)

pred

(pred p?)(pred p? pred-name)
A value for which p? returns true (and does not throw).
Optional pred-name can be passed for nicer validation errors.

protocol

macro

(protocol p)
A value that must satsify? protocol p.

Internaly, we must make sure not to capture the value of the protocol at
schema creation time, since that's impossible in cljs and breaks later
extends in Clojure.

A macro for cljs sake, since `satisfies?` is a macro in cljs.

protocol-name

(protocol-name protocol)

queue

(queue x)
Defines a schema satisfied by instances of clojure.lang.PersistentQueue
(clj.core/PersistentQueue in ClojureScript) whose values satisfy x.

queue?

(queue? x)

record

macro

(record klass schema)(record klass schema map-constructor)
A Record instance of type klass, whose elements match map schema 'schema'.

The final argument is the map constructor of the record type; if you do
not pass one, an attempt is made to find the corresponding function
(but this may fail in exotic circumstances).

record*

(record* klass schema map-constructor)

recursive

(recursive schema)
Support for (mutually) recursive schemas by passing a var that points to a schema,
e.g (recursive #'ExampleRecursiveSchema).

Regex

A regular expression

required-key

(required-key k)
A required key in a map

required-key?

(required-key? ks)

Schema

protocol

members

explain

(explain this)
Expand this schema to a human-readable format suitable for pprinting,
also expanding class schematas at the leaves.  Example:

user> (s/explain {:a s/Keyword :b [s/Int]} )
{:a Keyword, :b [Int]}

spec

(spec this)
A spec is a record of some type that expresses the structure of this schema
in a declarative and/or imperative way.  See schema.spec.* for examples.

schema-name

(schema-name schema)
Returns the name of a schema attached via schema-with-name (or defschema).

schema-ns

(schema-ns schema)
Returns the namespace of a schema attached via defschema.

schema-with-name

(schema-with-name schema name)
Records name in schema's metadata.

schematize-fn

(schematize-fn f schema)
Attach the schema to fn f at runtime, extractable by fn-schema.

set-compile-fn-validation!

macro

(set-compile-fn-validation! on?)

set-fn-validation!

(set-fn-validation! on?)
Globally turn on (or off) schema validation for all s/fn and s/defn instances.

set-max-value-length!

(set-max-value-length! max-length)
Sets the maximum length of value to be output before it is contracted to a prettier name.

specific-key?

(specific-key? ks)

Str

Satisfied only by String.
Is (pred string?) and not js/String in cljs because of keywords.

Symbol

A symbol

Uuid

The local representation of #uuid ...

validate

(validate schema value)
Throw an exception if value does not satisfy schema; otherwise, return value.
If you will be validating many datums, it is much more efficient to create
a 'validator' once and call it on each of them.

validator

(validator schema)
Compile an efficient validator for schema.

var-name

(var-name v)

with-fn-validation

macro

(with-fn-validation & body)
Execute body with input and output schema validation turned on for
all s/defn and s/fn instances globally (across all threads). After
all forms have been executed, resets function validation to its
previously set value. Not concurrency-safe.

without-fn-validation

macro

(without-fn-validation & body)
Execute body with input and output schema validation turned off for
all s/defn and s/fn instances globally (across all threads). After
all forms have been executed, resets function validation to its
previously set value. Not concurrency-safe.