Skip to content

JSON

JSON parsing starts with an unknown Term. A Decoder<A> checks that value at runtime and returns Result<A, DecodeError>, so successful decoding produces the exact Gale type requested by the caller. Encoding is explicit too: Encoder<A> produces Gale’s closed Json type, so values outside JSON’s data model cannot be encoded accidentally.

Profile is a nominal struct with a statically known JSON shape. Nullable JSON data is represented explicitly with Option<A>.

module json_example.profile
@moduledoc """
`Profile` is a nominal struct with a statically known JSON shape. Nullable
JSON data is represented explicitly with `Option<A>`.
"""
struct {
name: Binary,
age: Integer,
tags: List<Binary>,
nickname: Option<Binary>
}
pub fn profile_decoder() -> gale_std.decode.Decoder<Profile> {
fn(input) => {
with {
name <- gale_std.decode.field(input, "name", gale_std.decode.binary())
age <- gale_std.decode.field(input, "age", gale_std.decode.integer())
tags <- gale_std.decode.field(
input,
"tags",
gale_std.decode.list(gale_std.decode.binary())
)
nickname <- gale_std.decode.field(
input,
"nickname",
gale_std.decode.nullable(gale_std.decode.binary())
)
let profile = Profile {
name: name,
age: age,
tags: tags,
nickname: nickname
}
profile
}
}
}
pub fn profile_encoder() -> gale_std.json.Encoder<Profile> {
fn(profile) => gale_std.json.object([
("name", gale_std.json.string(profile.name)),
("age", gale_std.json.integer(profile.age)),
(
"tags",
gale_std.json.array(
profile.tags,
fn(tag) => gale_std.json.string(tag)
)
),
(
"nickname",
gale_std.json.nullable(
profile.nickname,
fn(nickname) => gale_std.json.string(nickname)
)
)
])
}

Encoding is explicit too. Encoder<A> produces Gale’s closed Json type; values outside JSON’s data model, such as PIDs, cannot be encoded accidentally.

Passing an arbitrary BEAM value is a type error:

pub fn encode_pid(pid: gale_std.process.Pid<Term>) -> Binary {
gale_std.json.encode(pid)
}

gale_std.json.parse(source, profile_decoder()) separates malformed JSON with JsonSyntaxError from a valid JSON value of the wrong shape with JsonValueError. Decode errors carry DecodeField and DecodeIndex paths.