package yocaml

  1. Overview
  2. Docs

Used to validate data described by type Yocaml.Data.t to build validation pipelines. The aim of this module is to produce combinators for building validation pipelines that support nesting and that can transform any value described by the AST in Data into arbitrary OCaml values.

Types

type custom_error = ..

An extensible type dedicated to extending potential validation errors.

type value_error =
  1. | Invalid_shape of {
    1. expected : string;
    2. given : t;
    }
  2. | Invalid_list of {
    1. errors : (int * value_error) Nel.t;
    2. given : t list;
    }
  3. | Invalid_record of {
    1. errors : record_error Nel.t;
    2. given : (string * t) list;
    }
  4. | With_message of {
    1. given : string;
    2. message : string;
    }
  5. | Custom of custom_error

Type used to describe when a value does not have the expected form (for example when a float is given whereas a character string is expected). The With_message is only parametrized by string in order to allow to write custom error messages.

and record_error =
  1. | Missing_field of {
    1. field : string;
    }
  2. | Invalid_field of {
    1. given : t;
    2. field : string;
    3. error : value_error;
    }

Errors at the field level, for validating records.

type 'a validated_value = ('a, value_error) result

Used to validate data described by type t to build validation pipelines.

type 'a validated_record = ('a, record_error Nel.t) result

Used to validate records described by type t to build validation pipelines.

Types helpers

Helpers for creating errors.

val fail_with : given:string -> string -> 'a validated_value

fail_with ~given message returns a validation error associated to a message.

val fail_with_custom : custom_error -> 'a validated_value

fail_with_custom err returns a custonm validation error.

Validators

Validators act on classic AST values. They are used to validate the fields of a record (or the inhabitants of a list). They are often used as arguments to the optional, optional_or and required functions.

val null : t -> unit validated_value

ensure that a value is null.

val bool : t -> bool validated_value

ensure that a value is a boolean.

val int : t -> int validated_value

ensure that a value is an int (or a float).

val float : t -> float validated_value

ensure that a value is an float.

val string : ?strict:bool -> t -> string validated_value

ensure that a value is a string, if strict is false it will consider bool, int, float also as strings.

val list_of : (t -> 'a validated_value) -> t -> 'a list validated_value

list_of v x ensure that x is a list that satisfy v (all errors are collected).

val record : ((string * t) list -> 'a validated_record) -> t -> 'a validated_value

record v x ensure that x has the shape validated by v (all errors are collected).

val option : (t -> 'a validated_value) -> t -> 'a option validated_value

option v x validate a value using v that can be null wrapped into an option.

val pair : (t -> 'a validated_value) -> (t -> 'b validated_value) -> t -> ('a * 'b) validated_value

pair fst snd x validated a pair (described as Yocaml.Data.pair, {"fst": a, "snd": b}).

val triple : (t -> 'a validated_value) -> (t -> 'b validated_value) -> (t -> 'c validated_value) -> t -> ('a * 'b * 'c) validated_value

triple f g h v define a triple validator built on top of pair. (Under the hood, it treat value like that (x, (y, z)). )

val quad : (t -> 'a validated_value) -> (t -> 'b validated_value) -> (t -> 'c validated_value) -> (t -> 'd validated_value) -> t -> ('a * 'b * 'c * 'd) validated_value

quad f g h i v define a quad validator built on top of triple. (Under the hood, it treat value like that (w, (x, (y, z))). )

val sum : (string * (t -> 'a validated_value)) list -> t -> 'a validated_value

sum [(k, v)] value validated a sum value using the representation described in Yocaml.Data.sum: {"constr": const_value, "value": e}.

val either : (t -> 'a validated_value) -> (t -> 'b validated_value) -> t -> ('a, 'b) Either.t validated_value

either left right v validated a either value.

Validators on parsed data

Validators to use when data is already parsed.

val positive : int -> int validated_value

positive x ensure that x is positive.

val positive' : float -> float validated_value

positive x ensure that x is positive.

val bounded : min:int -> max:int -> int -> int validated_value

bounded ~min ~max x ensure that x is included in the range [min;max] (both included).

val bounded' : min:float -> max:float -> float -> float validated_value

bounded ~min ~max x ensure that x is included in the range [min;max] (both included).

val non_empty : 'a list -> 'a list validated_value

non_empty l ensure that l is non-empty.

val equal : ?pp:(Format.formatter -> 'a -> unit) -> ?equal:('a -> 'a -> bool) -> 'a -> 'a -> 'a validated_value

equal ?pp ?equal x y ensure that y is equal to x. pp is used for error-reporting.

val not_equal : ?pp:(Format.formatter -> 'a -> unit) -> ?equal:('a -> 'a -> bool) -> 'a -> 'a -> 'a validated_value

not_equal ?pp ?equal x y ensure that y is different of x. pp is used for error-reporting.

val gt : ?pp:(Format.formatter -> 'a -> unit) -> ?compare:('a -> 'a -> int) -> 'a -> 'a -> 'a validated_value

gt ?pp ?equal x y ensure that x is greater than y. pp is used for error-reporting.

val ge : ?pp:(Format.formatter -> 'a -> unit) -> ?compare:('a -> 'a -> int) -> 'a -> 'a -> 'a validated_value

ge ?pp ?equal x y ensure that x is greater or equal to y. pp is used for error-reporting.

val lt : ?pp:(Format.formatter -> 'a -> unit) -> ?compare:('a -> 'a -> int) -> 'a -> 'a -> 'a validated_value

lt ?pp ?equal x y ensure that x is lesser than y. pp is used for error-reporting.

val le : ?pp:(Format.formatter -> 'a -> unit) -> ?compare:('a -> 'a -> int) -> 'a -> 'a -> 'a validated_value

le ?pp ?equal x y ensure that x is lesser or equal to y. pp is used for error-reporting.

val one_of : ?pp:(Format.formatter -> 'a -> unit) -> ?equal:('a -> 'a -> bool) -> 'a list -> 'a -> 'a validated_value

one_of ?pp ?equal li x ensure that x is include in li. pp is used for error-reporting.

val where : ?pp:(Format.formatter -> 'a -> unit) -> ?message:('a -> string) -> ('a -> bool) -> 'a -> 'a validated_value

where ?pp predicate x ensure that x is satisfying predicate. pp is used for error-reporting.

val const : 'a -> 'b -> ('a, 'c) result

const k r wrap k as valid and discard r.

Infix operators

module Infix : sig ... end

Infix operators are essentially used to compose data validators (unlike binding operators, which are used to compose record validation fragments).

val (&) : ('a -> 'b validated_value) -> ('b -> 'c validated_value) -> 'a -> 'c validated_value

(v1 & v2) x sequentially compose v2 (v1 x), so v1 following by v2. For example : int &> positive &> c.

val (/) : ('a -> 'b validated_value) -> ('a -> 'b validated_value) -> 'a -> 'b validated_value

(v1 / v2) x perform v1 x and if it fail, performs v2 x.

val ($) : ('a -> 'b validated_value) -> ('b -> 'c) -> 'a -> 'c validated_value

(v1 $ f) x perform f on the result of v1 x.

Fields validators

Field validators are used to describe parallel validation strategies for each field in a record and collect errors by field. Usually, a field validator takes as arguments the associative list of keys/values in a record, the name of the field to be observed and a regular validator.

val required : (string * t) list -> string -> (t -> 'a validated_value) -> 'a validated_record

required assoc field validator required field of assoc, validated by validator.

val optional : (string * t) list -> string -> (t -> 'a validated_value) -> 'a option validated_record

optional assoc field validator optional field of assoc, validated by validator.

val optional_or : (string * t) list -> string -> default:'a -> (t -> 'a validated_value) -> 'a validated_record

optional_or ~default assoc field validator optional field of assoc, validated by validator. If the field does not exists, it return default. (default is not validated)

Bindings operators

module Syntax : sig ... end

Binding operators are used to link fields together to build a complete validation.

val let+ : ('a, 'err) Result.t -> ('a -> 'b) -> ('b, 'err) Result.t

let+ x = v in k x is map (fun x -> k x) v.

val and+ : 'a validated_record -> 'b validated_record -> ('a * 'b) validated_record

let+ x = v and+ y = w in k x y is map2 (fun x y -> k x y) v w.

val let* : ('a, 'err) Result.t -> ('a -> ('b, 'err) Result.t) -> ('b, 'err) Result.t

let* r = f x in return r tries to produce a result Ok from the expression f x, if the expression returns Error _, the computation chain is interrupted.

Warning: the semantics of let* are significantly different from a succession of let+ ... and+ ... which allow errors to be collected in parallel (independently), whereas let* captures them sequentially. The composition of let* and let+ is tricky and let* should only be used to validate preconditions.

OCaml

Innovation. Community. Security.