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:
- It runs identically on the Erlang and JavaScript targets.
- It has no Erlang/OTP version requirement.
- Parse errors carry a precise byte position, on every runtime.
- The
Jsonvalue is a transparent type you can pattern match on, transform, and build directly — no opaque box.
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
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
-
UnexpectedEndThe input ended while a value was still expected.
-
UnexpectedByte(byte: String, position: Int)An unexpected byte was found at
position.byteis 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.
tokenis 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 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 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).