Module
pooka/json
src/pooka/json.pookaRead and write JSON, with Erlang's own json module doing the heavy
lifting.
A JSON document becomes a Json value: one of seven small classes, one
for each kind of thing JSON can say. Take it apart with match, or with
the helpers at the end of this module.
import pooka/json
main() {
let assert Ok(owl) = json.decode("{\"name\": \"Ada\", \"age\": 3}")
echo json.get(owl, "name")
echo json.encode(json.JArray([json.JInt(1), json.JNull()]))
}
Objects keep their entries in the order they were written, so a document that is decoded and encoded again comes back in the same order.
API reference
- classJson
- classJNull
- classJBool
- classJInt
- classJFloat
- classJString
- classJArray
- classJObject
- interfaceEncodable
- classJsonError
- classUnexpectedEnd
- classInvalidByte
- classUnexpectedSequence
- classNumberOutOfRange
- classLimitExceeded
- functiondecode
- functiondescribe
- functionencode
- functionencode_pretty
- functionencode_value
- functionencode_value_pretty
- functionget
- functionpath
- functionat
- functionas_string
- functionas_int
- functionas_float
- functionas_bool
- functionas_list
- functionas_entries
- functionis_null
- functiondecode_with_limits
class Json
Any JSON value.
class JNull is Json
null
class JBool(value: Bool) is Json
true or false
value: Bool
Bool
fn(Bool) -> pooka/json.JBoolclass JInt(value: Int) is Json
A number written without a fraction or exponent, such as 42.
value: Int
Int
fn(Int) -> pooka/json.JIntclass JFloat(value: Float) is Json
A number written with a fraction or exponent, such as 2.5 or 1e3.
value: Float
Float
fn(Float) -> pooka/json.JFloatclass JString(value: String) is Json
A string, with its escapes already resolved.
value: String
String
fn(String) -> pooka/json.JStringclass JArray(items: List(Json)) is Json
An array.
items: List(Json)
List(pooka/json.Json)
fn(List(pooka/json.Json)) -> pooka/json.JArrayclass JObject(entries: List(#(String, Json))) is Json
An object, as its entries in the order they were written. A key that
appears twice is kept twice; get returns the first.
entries: List(#(String, Json))
List(#(String, pooka/json.Json))
fn(List(#(String, pooka/json.Json))) -> pooka/json.JObjectinterface Encodable
A promise an application value can make without joining Json's closed family. The class chooses its JSON shape; the ordinary writers handle the text.
import pooka/json
import pooka/json.{Encodable}
class Bird(name: String) with Encodable {
to_json() -> json.Json {
json.JObject([#("name", json.JString(name))])
}
}
assert json.encode_value(Bird("Ada")) == "{\"name\":\"Ada\"}"
to_json() -> Json
Return the JSON representation. The writer calls this method once.
class JsonError
Why a text is not JSON.
class UnexpectedEnd is JsonError
The text stopped in the middle of a value.
class InvalidByte(byte: Int) is JsonError
A byte that cannot appear where it was found, as its numeric value.
byte: Int
Int
fn(Int) -> pooka/json.InvalidByteclass UnexpectedSequence(text: String) is JsonError
A broken escape or invalid UTF-8 inside a string.
text: String
String
fn(String) -> pooka/json.UnexpectedSequenceclass NumberOutOfRange(text: String) is JsonError
A syntactically valid number whose magnitude is outside the BEAM Float range.
text: String
String
fn(String) -> pooka/json.NumberOutOfRangeclass LimitExceeded(limit: String) is JsonError
An input byte or nesting limit was exceeded before building the value tree.
limit: String
String
fn(String) -> pooka/json.LimitExceededdecode(text: String) -> Result(Json, JsonError)
fn(String) -> Result(pooka/json.Json, pooka/json.JsonError)Read one JSON document.
import pooka/json
assert json.decode("[1, true]") == Ok(json.JArray([json.JInt(1), json.JBool(True)]))
assert json.decode("[1,") == Error(json.UnexpectedEnd())
describe(problem: JsonError) -> String
fn(pooka/json.JsonError) -> StringA sentence for the person who wrote the text.
import pooka/json
assert json.describe(json.UnexpectedEnd()) == "the JSON text ended too early"
encode(value: Json) -> String
fn(pooka/json.Json) -> StringWrite a value as compact JSON, with no spaces.
import pooka/json
let owl = json.JObject([#("name", json.JString("Ada")), #("age", json.JInt(3))])
assert json.encode(owl) == "{\"name\":\"Ada\",\"age\":3}"
encode_pretty(value: Json) -> String
fn(pooka/json.Json) -> StringWrite a value as JSON for people, indented by two spaces.
import pooka/json
assert json.encode_pretty(json.JArray([json.JInt(1), json.JInt(2)])) == "[\n 1,\n 2\n]"
encode_value(value: Encodable) -> String
fn(pooka/json.Encodable) -> StringWrite an application value through its Encodable promise, as compact JSON. Existing Json values continue to use encode directly.
// With the Bird class from Encodable's example:
assert json.encode_value(Bird("Ada")) == "{\"name\":\"Ada\"}"
encode_value_pretty(value: Encodable) -> String
fn(pooka/json.Encodable) -> StringWrite an application value through Encodable, indented by two spaces.
// With the Bird class from Encodable's example:
assert json.encode_value_pretty(Bird("Ada")) == "{\n \"name\": \"Ada\"\n}"
get(value: Json, key: String) -> Option(Json)
fn(pooka/json.Json, String) -> Option(pooka/json.Json)The value under a key, if this is an object that has it.
import pooka/json
let assert Ok(owl) = json.decode("{\"name\": \"Ada\"}")
assert json.get(owl, "name") == Some(json.JString("Ada"))
assert json.get(owl, "wings") == None
path(value: Json, keys: List(String)) -> Option(Json)
fn(pooka/json.Json, List(String)) -> Option(pooka/json.Json)Follow several keys, one object inside another.
import pooka/json
let assert Ok(nest) = json.decode("{\"owl\": {\"name\": \"Ada\"}}")
assert json.path(nest, ["owl", "name"]) == Some(json.JString("Ada"))
at(value: Json, index: Int) -> Option(Json)
fn(pooka/json.Json, Int) -> Option(pooka/json.Json)The item at a position, counting from zero, if this is an array that has it.
import pooka/json
let assert Ok(row) = json.decode("[10, 20]")
assert json.at(row, 1) == Some(json.JInt(20))
as_string(value: Json) -> Option(String)
fn(pooka/json.Json) -> Option(String)The text, if this is a string.
as_int(value: Json) -> Option(Int)
fn(pooka/json.Json) -> Option(Int)The number, if this is a whole number.
as_float(value: Json) -> Option(Float)
fn(pooka/json.Json) -> Option(Float)The number as a Float. JSON does not tell 3 from 3.0, so both are
accepted here.
as_bool(value: Json) -> Option(Bool)
fn(pooka/json.Json) -> Option(Bool)The truth value, if this is true or false.
as_list(value: Json) -> Option(List(Json))
fn(pooka/json.Json) -> Option(List(pooka/json.Json))The items, if this is an array.
as_entries(value: Json) -> Option(List(#(String, Json)))
fn(pooka/json.Json) -> Option(List(#(String, pooka/json.Json)))The entries, if this is an object.
is_null(value: Json) -> Bool
fn(pooka/json.Json) -> BoolIs this null?
decode_with_limits(text: String, max_bytes: Int, max_depth: Int) -> Result(
Json,
JsonError
)
fn(String, Int, Int) -> Result(pooka/json.Json, pooka/json.JsonError)Parse untrusted input with explicit byte and container-depth budgets. A scalar has depth zero. A negative budget rejects every input.
assert json.decode_with_limits("[[1]]", 100, 1) == Error(json.LimitExceeded("depth"))