gleamson

gleamson — a pure-Gleam JSON library.

Unlike libraries that delegate to a platform’s native JSON facilities, gleamson is written entirely in Gleam. That means:

Parsing is a single pass over a BitArray using Gleam’s bit-array pattern matching, which compiles to fast binary matching on the BEAM.

Types

A JSON value.

This type is transparent on purpose: you can pattern match on it, build it with its constructors, and walk it with the helpers in this module.

Object([
  #("game", String("Pac-Man")),
  #("score", Int(3_333_360)),
  #("flaws", Null),
])

Object entries keep their original order and allow duplicate keys, so a parse → encode round trip preserves the document faithfully. Use to_dict if you want O(1) repeated lookups instead.

pub type Json {
  Null
  Bool(Bool)
  Int(Int)
  Float(Float)
  String(String)
  Array(List(Json))
  Object(List(#(String, Json)))
}

Constructors

  • Null
  • Bool(Bool)
  • Int(Int)
  • Float(Float)
  • String(String)
  • Array(List(Json))
  • Object(List(#(String, Json)))

Everything that can go wrong while parsing, with a byte position where it is meaningful.

pub type ParseError {
  UnexpectedEnd
  UnexpectedByte(byte: String, position: Int)
  UnexpectedToken(token: String, position: Int)
}

Constructors

  • UnexpectedEnd

    The input ended while a value was still expected.

  • UnexpectedByte(byte: String, position: Int)

    An unexpected byte was found at position. byte is the offending character, or a short description / 0x.. hex if it is not printable.

  • UnexpectedToken(token: String, position: Int)

    A run of bytes that looked like a token but could not be interpreted, for example a malformed number. token is the offending text.

Values

pub fn array(
  from items: List(a),
  of encode: fn(a) -> Json,
) -> Json

Encode a list as a JSON array using a per-item encoder.

array(["a", "b"], of: String)
// -> Array([String("a"), String("b")])
pub fn as_bool(json: Json) -> Result(Bool, Nil)
pub fn as_float(json: Json) -> Result(Float, Nil)
pub fn as_int(json: Json) -> Result(Int, Nil)
pub fn as_string(json: Json) -> Result(String, Nil)
pub fn field(json: Json, named name: String) -> Result(Json, Nil)

Look up a key in an object.

pub fn from_dict(
  values: dict.Dict(k, v),
  keys: fn(k) -> String,
  encode: fn(v) -> Json,
) -> Json

Build an Object from a Dict.

pub fn get(
  json: Json,
  at path: List(String),
) -> Result(Json, Nil)

Follow a path of object keys.

get(value, at: ["user", "name"])
pub fn index(json: Json, at i: Int) -> Result(Json, Nil)

Index into an array.

pub fn merge(into base: Json, patch patch: Json) -> Json

Merge patch into base. Objects are merged recursively, a Null in the patch removes that key, and any non-object patch replaces the base value. Handy for layering configuration or applying partial updates.

merge(into: Object([#("a", Int(1)), #("b", Int(2))]), patch: Object([#("b", Null)]))
// -> Object([#("a", Int(1))])
pub fn nullable(
  from value: option.Option(a),
  of encode: fn(a) -> Json,
) -> Json

Encode an Option, using Null for None.

pub fn parse(from json: String) -> Result(Json, ParseError)

Parse a JSON string into a Json value.

parse("[1, 2, 3]")
// -> Ok(Array([Int(1), Int(2), Int(3)]))

parse("[")
// -> Error(UnexpectedEnd)
pub fn parse_bits(
  from json: BitArray,
) -> Result(Json, ParseError)

Parse JSON from a BitArray. Useful when the bytes come straight off the wire and you would rather not allocate an intermediate String.

pub fn pointer(json: Json, path: String) -> Result(Json, Nil)

Look up a value by a JSON Pointer string, e.g. "/user/items/0/id".

An empty string returns the whole document. Object keys containing / or ~ are escaped as ~1 and ~0 respectively, per RFC 6901.

pointer(value, "/a/b/1")   // 2nd element of a.b
pointer(value, "")         // the whole value
pointer(value, "/a~1b")    // the key "a/b"
pub fn semantically_equal(a: Json, b: Json) -> Bool

Compare two values for equality while ignoring the order of object keys. Arrays stay order-sensitive, since JSON arrays are ordered. Great for tests where == would be too strict about key order.

pub fn to_dict(
  json: Json,
) -> Result(dict.Dict(String, Json), Nil)

Convert an object to a Dict for repeated O(1) lookups. Later keys win on duplicates.

pub fn to_string(json: Json) -> String

Render a Json value to a compact string.

Prefer to_string_tree when feeding the BEAM’s IO, which is optimised for iodata.

to_string(Array([Int(1), Int(2), Int(3)]))
// -> "[1,2,3]"
pub fn to_string_pretty(json: Json) -> String

Render a Json value as indented, human-readable text using two spaces per nesting level.

to_string_pretty(Object([#("a", Int(1))]))
// -> "{\n  \"a\": 1\n}"
pub fn to_string_pretty_with(
  json: Json,
  spaces spaces: Int,
) -> String

Like to_string_pretty, but with a configurable number of spaces per level.

pub fn to_string_tree(json: Json) -> string_tree.StringTree

Render a Json value to a StringTree (iodata).

Search Document