package decoders

  1. Overview
  2. Docs

Derive decoders for a Decodeable.value.

Parameters

module M : Decodeable

Signature

type value = M.value

The type of values to be decoded (e.g. JSON or Yaml).

type error = value exposed_error
val pp_error : Format.formatter -> error -> unit
val string_of_error : error -> string
val of_string : string -> (value, error) result
val of_file : string -> (value, error) result
type 'a decoder = (M.value, 'a) exposed_decoder

The type of decoders.

Use the functions below to construct decoders for your data types.

To run a decoder, pass it to decode_value.

Primitives

val string : string decoder

Decode a string.

val int : int decoder

Decode an int.

val float : float decoder

Decode a float.

val bool : bool decoder

Decode a bool.

val null : unit decoder

Decode a null.

val value : value decoder

Decode a literal value.

Lists

val list : 'a decoder -> 'a list decoder

Decode a collection into an OCaml list.

val list_filter : 'a option decoder -> 'a list decoder

Decode a collection into an OCaml list, skipping elements for which the decoder returns None.

val list_fold_left : ('a -> 'a decoder) -> 'a -> 'a decoder

Decode a collection with an accumulator.

If we consider that an 'a decoder is basically a type alias for json -> ('a, error) result, the signature of this function is comparable to that of List.fold_left:

val List.fold_left : ('a ->   'b ->                 'a) -> 'a -> 'b list ->                 'a
val list_fold_left : ('a -> json -> ('a, error) result) -> 'a ->    json -> ('a, error) result
val list_fold_left : ('a ->                 'a decoder) -> 'a ->                    'a decoder
val array : 'a decoder -> 'a array decoder

Decode a collection into an OCaml array.

val index : int -> 'a decoder -> 'a decoder

Decode a collection, requiring a particular index.

val uncons : ('a -> 'b decoder) -> 'a decoder -> 'b decoder

fst |> uncons rest decodes the first element of a list using fst, then decodes the remainder of the list using rest.

For example, to decode this s-expression:

(library
  (name decoders))

we can use this decoder:

string |> uncons (function
  | "library" -> field "name" string
  | _ -> fail "Expected a library stanza")

As another example, say you have a JSON array that starts with a string, then a bool, then a list of integers:

["hello", true, 1, 2, 3, 4]

We could decode it like this:

let (>>=::) fst rest = uncons rest fst

let decoder : (string * bool * int list) decoder =
  string >>=:: fun the_string ->
  bool >>=:: fun the_bool ->
  list int >>= fun the_ints ->
  succeed (the_string, the_bool, the_ints)

(If you squint, the uncons operator >>=:: kind of looks like the cons operator ::.)

Object primitives

val field : string -> 'a decoder -> 'a decoder

Decode an object, requiring a particular field.

val field_opt : string -> 'a decoder -> 'a option decoder

Decode an object, where a particular field may or may not be present.

For example, (field_opt "hello" int):

  • when run on {"hello": 123}, will succeed with Some 123
  • when run on {"hello": null}, will fail
  • when run on {"world": 123}, will succeed with None
  • when run on ["a", "list", "of", "strings"], will fail
val single_field : (string -> 'a decoder) -> 'a decoder

Decode an object, requiring exactly one field.

val at : string list -> 'a decoder -> 'a decoder

Decode a nested object, requiring certain fields.

Inconsistent structure

val maybe : 'a decoder -> 'a option decoder

maybe d is a decoder that always succeeds. If d succeeds with x, then maybe d succeeds with Some x, otherwise if d fails, then maybe d succeeds with None.

For example, maybe (field "hello" int):

  • when run on {"hello": 123}, will succeed with Some 123
  • when run on {"hello": null}, will succeed with None
  • when run on {"world": 123}, will succeed with None
  • when run on ["a", "list", "of", "strings"], will succeed with None
val nullable : 'a decoder -> 'a option decoder

nullable d will succeed with None if the JSON value is null. If the JSON value is non-null, it wraps the result of running x in a Some.

For example, field "hello" (nullable int):

  • when run on {"hello": 123}, will succeed with Some 123
  • when run on {"hello": null}, will succeed with None
  • when run on {"world": 123}, will fail
  • when run on ["a", "list", "of", "strings"], will fail
val one_of : (string * 'a decoder) list -> 'a decoder

Try a sequence of different decoders.

Mapping

val map : ('a -> 'b) -> 'a decoder -> 'b decoder

Map over the result of a decoder.

val apply : ('a -> 'b) decoder -> 'a decoder -> 'b decoder

Try two decoders and then combine the result. We can use this to decode objects with many fields (but it's preferable to use Infix.(>>=) - see the README).

Working with object keys

val keys : string list decoder

Decode all of the keys of an object to a list of strings.

val key_value_pairs : 'v decoder -> (string * 'v) list decoder

Decode an object into a list of key-value pairs.

val key_value_pairs_seq : (string -> 'v decoder) -> 'v list decoder

Decode an object into a list of values, where the value decoder depends on the key.

val keys' : 'k decoder -> 'k list decoder

keys' is for when your keys might not be strings - probably only likely for Yaml.

val key_value_pairs' : 'k decoder -> 'v decoder -> ('k * 'v) list decoder
val key_value_pairs_seq' : 'k decoder -> ('k -> 'v decoder) -> 'v list decoder

Fancy decoding

val succeed : 'a -> 'a decoder

A decoder that always succeeds with the argument, ignoring the input.

val fail : string -> 'a decoder

A decoder that always fails with the given message, ignoring the input.

val fail_with : error -> 'a decoder
val from_result : ('a, error) result -> 'a decoder
val and_then : ('a -> 'b decoder) -> 'a decoder -> 'b decoder

Create decoders that depend on previous results.

val fix : ('a decoder -> 'a decoder) -> 'a decoder

Recursive decoders.

let my_decoder = fix (fun my_decoder -> ...) allows you to define my_decoder in terms of itself.

val of_of_string : msg:string -> (string -> 'a option) -> 'a decoder

Create a decoder from a function of_string : string -> 'a option

module Infix : sig ... end
include module type of Infix
val (>|=) : 'a decoder -> ('a -> 'b) -> 'b decoder
val (>>=) : 'a decoder -> ('a -> 'b decoder) -> 'b decoder
val (<*>) : ('a -> 'b) decoder -> 'a decoder -> 'b decoder
val (<$>) : ('a -> 'b) -> 'a decoder -> 'b decoder
val let+ : 'a decoder -> ('a -> 'b) -> 'b decoder
val and+ : 'a decoder -> 'b decoder -> ('a * 'b) decoder
val let* : 'a decoder -> ('a -> 'b decoder) -> 'b decoder
val and* : 'a decoder -> 'b decoder -> ('a * 'b) decoder

Running decoders

val decode_value : 'a decoder -> value -> ('a, error) result

Run a decoder on some input.

val decode_string : 'a decoder -> string -> ('a, error) result

Run a decoder on a string.

val decode_file : 'a decoder -> string -> ('a, error) result

Run a decoder on a file.

module Pipeline : sig ... end
OCaml

Innovation. Community. Security.