decipher

Functions

pub fn all(
  decoders: List(fn(Dynamic) -> Result(a, List(DecodeError))),
) -> fn(Dynamic) -> Result(List(a), List(DecodeError))

Create a decoder for a list of values from a list of decoders to run. Each decoder will run against the input value, and all must succeed for the decoder to succeed.

Errors from each decoder will be collected, which means the entire list is run even if one decoder fails!

pub fn arraylike(
  decoder: fn(Dynamic) -> Result(a, List(DecodeError)),
) -> fn(Dynamic) -> Result(List(a), List(DecodeError))

In JavaScript certain objects are said to be “arraylike”. These are objects that satisfy the following conditions:

  • They have a length property that is a non-negative integer.
  • They have a property for each integer index from 0 up to length - 1.

Operations like document.querySelectorAll or document.getElementsByTagName return arraylike objects like a NodeList. This decoder is capable of decoding such objects into a proper Gleam List.

pub fn at(
  path: List(String),
  decoder: fn(Dynamic) -> Result(a, List(DecodeError)),
) -> fn(Dynamic) -> Result(a, List(DecodeError))

Decode a value at a given key path. This decoder is permissive and will use index for any numeric string keys where possible.

pub fn base16(
  dynamic: Dynamic,
) -> Result(BitArray, List(DecodeError))

Decode a string representing base16-encoded binary data into a BitArray.

pub fn base64(
  dynamic: Dynamic,
) -> Result(BitArray, List(DecodeError))

Decode a string representing base64-encoded binary data into a BitArray.

pub fn base64_url_encoded(
  dynamic: Dynamic,
) -> Result(BitArray, List(DecodeError))

Decode a string representing url-safe base64-encoded binary data into a BitArray.

pub fn bool_string(
  dynamic: Dynamic,
) -> Result(Bool, List(DecodeError))

Decode a string that represents a YAML-style boolean value. Any of the following values will be decoded as True:

  • “true”
  • “True”
  • “on”
  • “On”
  • “yes”
  • “Yes”

Any of the following values will be decoded as False:

  • “false”
  • “False”
  • “off”
  • “Off”
  • “no”
  • “No”

Anything else will fail to decode.

pub fn enum(
  variants: List(#(String, a)),
) -> fn(Dynamic) -> Result(a, List(DecodeError))

A simplified version of the tagged_union decoder. First decodes a string, and then attempts to find a corresponding value from a list of variants.

This is how the bool_string decoder is implemented:

import decipher
import gleam/dynamic.{type DecodeError, type Decoder, type Dynamic, DecodeError}

pub fn bool_string(dynamic: Dynamic) -> Result(Bool, List(DecodeError)) {
  decipher.enum([
    #("true", True),
    #("True", True),
    #("on", True),
    #("On", True),
    #("yes", True),
    #("Yes", True),
    #("false", False),
    #("False", False),
    #("off", False),
    #("Off", False),
    #("no", False),
    #("No", False),
  ])(dynamic)
}
pub fn exact_object1(
  constructor: fn(a) -> b,
  field1: #(String, fn(Dynamic) -> Result(a, List(DecodeError))),
) -> fn(Dynamic) -> Result(b, List(DecodeError))

Decode an object with exactly one field into some value. If additional fields are present, decoding will fail and the additional fields will be reported in the error.

pub fn exact_object2(
  constructor: fn(a, b) -> c,
  field1: #(String, fn(Dynamic) -> Result(a, List(DecodeError))),
  field2: #(String, fn(Dynamic) -> Result(b, List(DecodeError))),
) -> fn(Dynamic) -> Result(c, List(DecodeError))

Decode an object with exactly two fields into some value. If additional fields are present, decoding will fail and the additional fields will be reported in the error.

pub fn exact_object3(
  constructor: fn(a, b, c) -> d,
  field1: #(String, fn(Dynamic) -> Result(a, List(DecodeError))),
  field2: #(String, fn(Dynamic) -> Result(b, List(DecodeError))),
  field3: #(String, fn(Dynamic) -> Result(c, List(DecodeError))),
) -> fn(Dynamic) -> Result(d, List(DecodeError))

Decode an object with exactly three fields into some value. If additional fields are present, decoding will fail and the additional fields will be reported in the error.

pub fn exact_object4(
  constructor: fn(a, b, c, d) -> e,
  field1: #(String, fn(Dynamic) -> Result(a, List(DecodeError))),
  field2: #(String, fn(Dynamic) -> Result(b, List(DecodeError))),
  field3: #(String, fn(Dynamic) -> Result(c, List(DecodeError))),
  field4: #(String, fn(Dynamic) -> Result(d, List(DecodeError))),
) -> fn(Dynamic) -> Result(e, List(DecodeError))

Decode an object with exactly four fields into some value. If additional fields are present, decoding will fail and the additional fields will be reported in the error.

pub fn exact_object5(
  constructor: fn(a, b, c, d, e) -> f,
  field1: #(String, fn(Dynamic) -> Result(a, List(DecodeError))),
  field2: #(String, fn(Dynamic) -> Result(b, List(DecodeError))),
  field3: #(String, fn(Dynamic) -> Result(c, List(DecodeError))),
  field4: #(String, fn(Dynamic) -> Result(d, List(DecodeError))),
  field5: #(String, fn(Dynamic) -> Result(e, List(DecodeError))),
) -> fn(Dynamic) -> Result(f, List(DecodeError))

Decode an object with exactly five fields into some value. If additional fields are present, decoding will fail and the additional fields will be reported in the error.

pub fn exact_object6(
  constructor: fn(a, b, c, d, e, f) -> g,
  field1: #(String, fn(Dynamic) -> Result(a, List(DecodeError))),
  field2: #(String, fn(Dynamic) -> Result(b, List(DecodeError))),
  field3: #(String, fn(Dynamic) -> Result(c, List(DecodeError))),
  field4: #(String, fn(Dynamic) -> Result(d, List(DecodeError))),
  field5: #(String, fn(Dynamic) -> Result(e, List(DecodeError))),
  field6: #(String, fn(Dynamic) -> Result(f, List(DecodeError))),
) -> fn(Dynamic) -> Result(g, List(DecodeError))

Decode an object with exactly six fields into some value. If additional fields are present, decoding will fail and the additional fields will be reported in the error.

pub fn exact_set(
  decoder: fn(Dynamic) -> Result(a, List(DecodeError)),
) -> fn(Dynamic) -> Result(Set(a), List(DecodeError))

Decode a list or arraylike into a Set. This decoder is slightly slower than the set decoder, but it will guarantee that there were no duplicate values in the incoming list.

pub fn float_string(
  dynamic: Dynamic,
) -> Result(Float, List(DecodeError))

Decode a Float that has been converted to a string. Some JSON APIs will send numbers as strings, so this decoder can come in handy more often than you’d think!

pub fn http_date(
  dynamic: Dynamic,
) -> Result(Time, List(DecodeError))

Decode a string representing a HTTP-date as a Time value from the birl package.

pub fn index(
  idx: Int,
  decoder: fn(Dynamic) -> Result(a, List(DecodeError)),
) -> fn(Dynamic) -> Result(a, List(DecodeError))

Decode a value at a given index. This decoder is permissive and will try to decode tuples, objects with string integer keys, and in the worst case will decode a list and index into that.

For strict tuple access, use the element decoder from the standard library.

pub fn int_string(
  dynamic: Dynamic,
) -> Result(Int, List(DecodeError))

Decode an Int that has been converted to a string. Some JSON APIs will send numbers as strings, so this decoder can come in handy more often than you’d think!

pub fn iso_8601(
  dynamic: Dynamic,
) -> Result(Time, List(DecodeError))

Decode a string representing an ISO 8601 datetime as a Time value from the birl package.

pub fn json_string(
  decoder: fn(Dynamic) -> Result(a, List(DecodeError)),
) -> fn(Dynamic) -> Result(a, List(DecodeError))

Occasionally you might find yourself in the situation where a JSON string is embedded in the dynamic value you’re trying to decode. This decoder lets you extract that JSON and then run the decoder against it.

pub fn keys(
  dynamic: Dynamic,
) -> Result(List(String), List(DecodeError))

Decode just the keys of an object as a list of strings.

pub fn non_empty_list(
  decode: fn(Dynamic) -> Result(a, List(DecodeError)),
) -> fn(Dynamic) -> Result(List(a), List(DecodeError))

Decode a list or arraylike with at least one item into a List. If the incoming list is empty, decoding will fail.

pub fn non_empty_string(
  dynamic: Dynamic,
) -> Result(String, List(DecodeError))

This decoder will decode a string and then confirm that it is not empty.

pub fn non_negative_int(
  dynamic: Dynamic,
) -> Result(Int, List(DecodeError))

Decode an Int as long as it is greater than or equal to zero.

pub fn number(
  dynamic: Dynamic,
) -> Result(Float, List(DecodeError))

This decoder is capable of decoding both Int and Float values. If the value is an Int, it will be converted to a Float automatically.

pub fn number_string(
  dynamic: Dynamic,
) -> Result(Float, List(DecodeError))

Decode numbers that have been converted to strings. This decoder is capable of decoding both Int and Float values converted to strings. Some JSON APIs will send numbers as strings, so this decoder can come in handy more often than you’d think!

pub fn semver(
  dynamic: Dynamic,
) -> Result(Version, List(DecodeError))

Decode a string representing a valid semantic version into a Version value from the stoiridh_version package.

pub fn set(
  decoder: fn(Dynamic) -> Result(a, List(DecodeError)),
) -> fn(Dynamic) -> Result(Set(a), List(DecodeError))

Decode a list or arraylike into a Set. Any duplicate values will be dropped. If you want to ensure that there are no duplicates, use the exact_set decoder instead.

pub fn tagged_union(
  tag: fn(Dynamic) -> Result(a, List(DecodeError)),
  variants: List(
    #(a, fn(Dynamic) -> Result(b, List(DecodeError))),
  ),
) -> fn(Dynamic) -> Result(b, List(DecodeError))

There is no standard way to represent something like Gleam’s custom types as JSON or YAML (or most common formats). It’s common then to represent them as a tagged or discriminated union where a field is used to signify which variant of the type is being represented.

This decoder lets you decode things in this format by first decoding the tag and then selecting the appropriate decoder to run based on that tag.

import decipher
import gleam/dynamic.{type DecodeError, type Decoder, type Dynamic, DecodeError}

type Example {
  Wibble(foo: Int)
  Wobble(bar: String)
}

fn example_decoder(dynamic: Dynamic) -> Result(Example, List(DecodeError)) {
  decipher.tagged_union(
    dynamic.field("$", dynamic.string),
    [
      #("wibble", dynamic.decode1(Wibble, dynamic.field("foo", dynamic.int))),
      #("wobble", dynamic.decode1(Wobble, dynamic.field("bar", dynamic.string))),
    ]
  )(dynamic)
}
pub fn unix_timestamp(
  dynamic: Dynamic,
) -> Result(Time, List(DecodeError))

Decode a Unix timestamp as a Time value from the birl package.

pub fn uri(dynamic: Dynamic) -> Result(Uri, List(DecodeError))

Decode a string representing a URI into a Gleam Uri value.

pub fn when(
  decoder: fn(Dynamic) -> Result(a, List(DecodeError)),
  is predicate: fn(a) -> Bool,
) -> fn(Dynamic) -> Result(a, List(DecodeError))

Run a decoder but only keep the result if it satisfies the given predicate. This is how decoders like non_negative_int can be implemented:

import decipher
import gleam/dynamic.{type DecodeError, type Decoder, type Dynamic, DecodeError}

pub fn non_negative_int(dynamic: Dynamic) -> Result(Int, List(DecodeError)) {
  decipher.when(dynamic.int, is: fn(x) { x >= 0 })(dynamic)
}
Search Document