Alpha. Vary is under active development and not ready for production use. Syntax, APIs, performance, and behaviour may change between releases.

JSON

Namespace rule

import json gates access to the Json, JsonValue, JsonError, JsonReader,
and JsonStreamWriter types. Use type-static methods and instance methods:

import json

let j = Json.parse("{\"name\": \"Alice\"}").unwrap()
let text = j.stringify()

The compiler enforces the import: using Json.parse() without import json
is a compile error.

Tree API

Json.parse() returns a typed Result[Json, JsonError]:

let result = Json.parse("{\"name\": \"Alice\", \"age\": 30}")
if result.is_ok() {
    let json = result.unwrap()
    let name = json.get_str("name")     # Str? "Alice"
    let age = json.get_int("age")       # Int? 30
}

Convenience accessors: get_str, get_int, get_float, get_bool, get_list.

Static methods

MethodReturnsDescription
Json.parse(text)Result[Json, JsonError]Parse a JSON string
Json.parse_bytes(b)Result[Json, JsonError]Parse UTF-8 bytes
Json.from_str(s)JsonCreate a string value
Json.from_int(i)JsonCreate an integer value
Json.from_float(d)JsonCreate a float value
Json.from_bool(b)JsonCreate a boolean value
Json.null_value()JsonCreate a null value
Json.empty_object()JsonCreate an empty mutable object

Instance methods

MethodReturnsDescription
.stringify()StrCompact JSON string
.stringify_pretty()StrIndented JSON string
.stringify_to_bytes()BytesCompact JSON as UTF-8 bytes
.get_path(path)Json?Dot-notation path access (e.g., "items.0.name")
.require_path(path)Result[Json, JsonError]Path access with error context

JSON Pointer (RFC 6901) navigates nested structures:

let json = Json.parse("{\"a\":{\"b\":[1,2,3]}}").unwrap()
let val = json.pointer_get("/a/b/1")

Require methods return Result[T, JsonError]:

let name = json.require_str("/user/name")

Streaming API

For large documents, use JsonReader for pull-based parsing and JsonStreamWriter for incremental building:

let reader = JsonReader.from_str('{"name":"Alice"}').unwrap()
let token = reader.next().unwrap()
reader.close()
let w = JsonStreamWriter.create()
w.begin_object()
w.key("name")
w.str_value("Alice")
w.end_object()
let json = w.finish()

Mutable building

Build JSON objects programmatically:

let obj = Json.empty_object()
obj.set_str("name", "Alice")
obj.set_int("age", 30)
obj.set_bool("active", True)
MethodReturnsDescription
Json.empty_object()JsonCreate an empty mutable object
.set_str(key, value)JsonSet a string field
.set_int(key, value)JsonSet an integer field
.set_bool(key, value)JsonSet a boolean field
.set_list(key, value)JsonSet a list field
.set(key, json)JsonSet a nested Json value

All setters return self for method chaining.

Typed decode DSL

For structured, validated JSON extraction, use Decoder (gated by import json). See JSON decode for the full reference.

import json

let node = json.decode("{\"name\": \"Alice\", \"age\": 30}")?
let name = node.field("name").str()?        # Result[Str, DecodeError]
let age = node.field("age").int()?          # Result[Int, DecodeError]
let role = node.field("role").str_or("guest")  # Str (default if missing)

Navigate nested structures with chained .field() calls. Errors include the full
path (e.g., "config.db.port") and expected/actual types.

MethodDescriptionReturns
str()Decode as stringResult[Str, DecodeError]
int()Decode as integerResult[Int, DecodeError]
float()Decode as floatResult[Float, DecodeError]
bool()Decode as booleanResult[Bool, DecodeError]
object()Decode as objectResult[Decoder, DecodeError]
list()Decode as list of nodesResult[List[Decoder], DecodeError]
enum(variants)Decode as one of allowed stringsResult[Str, DecodeError]
str_or_none()String if presentStr?
int_or_none()Integer if presentInt?
float_or_none()Float if presentFloat?
bool_or_none()Boolean if presentBool?
object_or_none()Object if presentDecoder?
list_or_none()List if presentList[Decoder]?
str_or(default)String with fallbackStr
int_or(default)Integer with fallbackInt
float_or(default)Float with fallbackFloat
bool_or(default)Boolean with fallbackBool
field(name)Navigate to child fieldDecoder
at(index)Navigate to list elementResult[Decoder, DecodeError]
keys()List object keysList[Str]
size()Number of elementsInt
path()Current node pathStr
validate_int(msg, check)Validate integer with predicateResult[Int, DecodeError]
validate_str(msg, check)Validate string with predicateResult[Str, DecodeError]
transform_str(fn)Transform string valueResult[Str, DecodeError]

DecodeError has .path(), .expected(), .actual(), and .message() methods.