json(3)
β¨ NAME β¨
json β yep, that's this page, json(3) π it's a whole library for encoding and decoding JSON, and honestly? she serves. π«Ά
πΈ DESCRIPTION πΈ
okay so first thing: this module implements EEP68. π
And like β both the encoder and the decoder fully conform to RFC 8259 and ECMA 404 standards, no cap. The decoder is tested using JSONTestSuite, so the vibes are certified. π§ͺβ¨
π¦ DATA TYPES π¦
here's the whole cast of characters bestie, catch them all π
array_finish_fun()β the "ok we're done with this array" callback
array_finish_fun() ::
fun((ArrayAcc :: dynamic(), OldAcc :: dynamic()) ->
{dynamic(), dynamic()}).
array_push_fun()β pushes one value onto the array accumulator
array_push_fun() ::
fun((Value :: dynamic(), Acc :: dynamic()) ->
NewAcc :: dynamic()).
array_start_fun()β kicks off a fresh array accumulator
array_start_fun() ::
fun((Acc :: dynamic()) -> ArrayAcc :: dynamic()).
continuation_state()β it's-opaque, so do not go poking at her insides π
-opaque continuation_state()
decode_value()β every kind of value the decoder can hand back to you
decode_value() ::
integer() |
float() |
boolean() |
null |
binary() |
[decode_value()] |
#{binary() => decode_value()}.
decoders()β the callback map you feed todecode/3
decoders() ::
#{array_start => array_start_fun(),
array_push => array_push_fun(),
array_finish => array_finish_fun(),
object_start => object_start_fun(),
object_push => object_push_fun(),
object_finish => object_finish_fun(),
float => from_binary_fun(),
integer => from_binary_fun(),
string => from_binary_fun(),
null => term()}.
encode_map(Value)β a map that can be encoded as a JSON object, withbinary(),atom()orinteger()keys
encode_map(Value) :: #{binary() | atom() | integer() => Value}.
encode_value()β a simple JSON value encodeable withjson:encode/1
encode_value() ::
integer() |
float() |
boolean() |
null |
binary() |
atom() |
[encode_value()] |
encode_map(encode_value()).
encoder()β the encode callback shape
encoder() :: fun((dynamic(), encoder()) -> iodata()).
formatter()β the formatter callback shape
formatter() ::
fun((Term :: dynamic(),
Encoder :: formatter(),
State :: map()) ->
iodata()).
from_binary_fun()β takes abinary(), gives you backdynamic()
from_binary_fun() :: fun((binary()) -> dynamic()).
object_finish_fun()β the "ok we're done with this object" callback
object_finish_fun() ::
fun((ObjectAcc :: dynamic(), OldAcc :: dynamic()) ->
{dynamic(), dynamic()}).
object_push_fun()β pushes a key + value pair onto the object accumulator
object_push_fun() ::
fun((Key :: dynamic(), Value :: dynamic(), Acc :: dynamic()) ->
NewAcc :: dynamic()).
object_start_fun()β kicks off a fresh object accumulator
object_start_fun() ::
fun((Acc :: dynamic()) -> ObjectAcc :: dynamic()).
π FUNCTIONS π
π decode/1 π
decode(binary()) -> decode_value().
Reads one JSON value out of Binary. π«Ά
The basic data mapping it's working with is this:
- JSON
Numberβ Erlanginteger(),float() - JSON
Booleanβ Erlangtrue,false - JSON
Nullβ Erlangnull - JSON
Stringβ Erlangbinary() - JSON
Objectβ Erlang#{binary() => _}
π Errors π
error(unexpected_end)ifBinarycontains incomplete JSON valueerror({invalid_byte, Byte})ifBinarycontains unexpected byte or invalid UTF-8 byteerror({unexpected_sequence, Bytes})ifBinarycontains invalid UTF-8 escape
β¨ Example β¨
> json:decode(<<"{\"foo\": 1}">>).
#{<<"foo">> => 1}
π decode/3 π
decode(binary(), dynamic(), decoders()) ->
{Result :: dynamic(), Acc :: dynamic(), binary()}.
Parses a JSON value from Binary, same energy as decode/1, except you get to customize the whole decoding process with the callbacks you specify in Decoders. Those callbacks use the Acc value as their initial accumulator.
And any leftover, unparsed data in Binary will be returned to you too. π
π Default callbacks π
All callbacks are optional. If you don't provide them, they fall back to the implementations used by the decode/1 function:
- for
array_start:fun(_) -> [] end - for
array_push:fun(Elem, Acc) -> [Elem | Acc] end - for
array_finish:fun(Acc, OldAcc) -> {lists:reverse(Acc), OldAcc} end - for
object_start:fun(_) -> [] end - for
object_push:fun(Key, Value, Acc) -> [{Key, Value} | Acc] end - for
object_finish:fun(Acc, OldAcc) -> {maps:from_list(Acc), OldAcc} end - for
float:fun erlang:binary_to_float/1 - for
integer:fun erlang:binary_to_integer/1 - for
string:fun (Value) -> Value end - for
null: the atomnull
π Errors π
error({invalid_byte, Byte})ifBinarycontains unexpected byte or invalid UTF-8 byteerror({unexpected_sequence, Bytes})ifBinarycontains invalid UTF-8 escapeerror(unexpected_end)ifBinarycontains incomplete JSON value
β¨ Example β¨
Decoding object keys as atoms:
> Push = fun(Key, Value, Acc) -> [{binary_to_existing_atom(Key), Value} | Acc] end.
> json:decode(<<"{\"foo\": 1}">>, ok, #{object_push => Push}).
{#{foo => 1},ok,<<>>}
π decode_continue/2 π
decode_continue(binary() | end_of_input,
State :: continuation_state()) ->
{Result :: dynamic(),
Acc :: dynamic(),
binary()} |
{continue, continuation_state()}.
Continue parsing a stream of bytes of a JSON value. π
Similar to decode_start/3, if the function returns {continue, State} and there is no more data, use end_of_input instead of a binary.
> {continue, State} = json:decode_start(<<"{\"foo\":">>, ok, #{}).
> json:decode_continue(<<"1}">>, State).
{#{foo => 1},ok,<<>>}
> {continue, State} = json:decode_start(<<"123">>, ok, #{}).
> json:decode_continue(end_of_input, State).
{123,ok,<<>>}
π decode_start/3 π
decode_start(binary(), dynamic(), decoders()) ->
{Result :: dynamic(), Acc :: dynamic(), binary()} |
{continue, continuation_state()}.
Begin parsing a stream of bytes of a JSON value. π
Similar to decode/3, but it returns as soon as a complete JSON value can be parsed β or it returns {continue, State} for incomplete data, and that State can be fed to the decode_continue/2 function when more data shows up.
π encode/1 π
encode(encode_value()) -> iodata().
Generates JSON corresponding to Term. π
The basic data mapping it's working with:
- Erlang
integer(),float()β JSON Number - Erlang
true,falseβ JSON Boolean - Erlang
nullβ JSON Null - Erlang
binary()β JSON String - Erlang
atom()β JSON String - Erlang
list()β JSON Array - Erlang
#{binary() => _}β JSON Object - Erlang
#{atom() => _}β JSON Object - Erlang
#{integer() => _}β JSON Object
This is equivalent to encode(Term, fun json:encode_value/2).
β¨ Examples β¨
> iolist_to_binary(json:encode(#{foo => <<"bar">>})).
<<"{\"foo\":\"bar\"}">>
π encode/2 π
encode(dynamic(), encoder()) -> iodata().
Generates JSON corresponding to Term, and you can customize it with the Encoder callback. That callback will be recursively called for all the data to be encoded and is expected to return the corresponding encoded JSON as iodata.
Various encode_* functions in this module can be used to help in constructing such callbacks. π οΈ
β¨ Examples β¨
An encoder that uses a heuristic to differentiate object-like lists of key-value pairs from plain lists:
> encoder([{_, _} | _] = Value, Encode) -> json:encode_key_value_list(Value, Encode);
> encoder(Other, Encode) -> json:encode_value(Other, Encode).
> custom_encode(Value) -> json:encode(Value, fun(Value, Encode) -> encoder(Value, Encode) end).
> iolist_to_binary(custom_encode([{a, []}, {b, 1}])).
<<"{\"a\":[],\"b\":1}">>
π encode_atom/2 π
encode_atom(atom(), encoder()) -> iodata().
The default encoder for atoms, used by json:encode/1. π
It encodes the atom null as JSON null, the atoms true and false as JSON booleans, and everything else as JSON strings β calling the Encode callback with the corresponding binary.
π encode_binary/1 π
encode_binary(binary()) -> iodata().
The default encoder for binaries as JSON strings, used by json:encode/1. π
π Errors π
error(unexpected_end)if the binary contains incomplete UTF-8 sequences.error({invalid_byte, Byte})if the binary contains invalid UTF-8 sequences.
π encode_binary_escape_all/1 π
encode_binary_escape_all(binary()) -> iodata().
Encoder for binaries as JSON strings that produces pure-ASCII JSON. β¨
For any non-ASCII unicode character, a corresponding \\uXXXX sequence is used.
π Errors π
error(unexpected_end)if the binary contains incomplete UTF-8 sequences.error({invalid_byte, Byte})if the binary contains invalid UTF-8 sequences.
π encode_float/1 π
encode_float(float()) -> iodata().
The default encoder for floats as JSON numbers, used by json:encode/1. π₯
π encode_integer/1 π
encode_integer(integer()) -> iodata().
Default encoder for integers as JSON numbers used by json:encode/1. π
encode_key_value_list([{term(), term()}], encoder()) -> iodata().β okay so this is the encoder for lists of key-value pairs as JSON objects. It accepts lists with atom, binary, integer, or float keys. Slay. β¨encode_key_value_list_checked([{term(), term()}], encoder()) -> iodata().β same encoder for lists of key-value pairs as JSON objects. Accepts lists with atom, binary, integer, or float keys. BUT it verifies that no duplicate keys will be produced in the resulting JSON object. Highkey important. π
Errors
Raises error({duplicate_key, Key}) if there are duplicates. π
encode_list(list(), encoder()) -> iodata().β default encoder for lists as JSON arrays used byjson:encode/1. It's giving array energy. πencode_map(encode_map(dynamic()), encoder()) -> iodata().β default encoder for maps as JSON objects used byjson:encode/1. Accepts maps with atom, binary, integer, or float keys. Main character map vibes. πΊοΈencode_map_checked(map(), encoder()) -> iodata().β encoder for maps as JSON objects. Accepts maps with atom, binary, integer, or float keys. Verifies that no duplicate keys will be produced in the resulting JSON object. The way it checks... obsessed. π΅οΈ
Errors
Raises error({duplicate_key, Key}) if there are duplicates.
encode_value(dynamic(), encoder()) -> iodata().β default encoder used byjson:encode/1. Recursively callsEncodeon all the values inValue. It goes deep, bestie. πformat(Term :: encode_value()) -> iodata().β generates formatted JSON corresponding toTerm. Similar toencode/1but with added whitespaces for formatting. So pretty. β¨
> io:put_chars(json:format(#{foo => <<"bar">>, baz => 52})).
{
"baz": 52,
"foo": "bar"
}
ok
format(Term :: encode_value(), Opts :: map()) -> iodata();(Term :: dynamic(), Encoder :: formatter()) -> iodata().β generates formatted JSON corresponding toTerm. Equivalent toformat(Term, fun json:format_value/3, Options)orformat(Term, Encoder, #{}). Two paths, one slay. πformat(Term :: dynamic(), Encoder :: formatter(), Options :: map()) -> iodata().β generates formatted JSON corresponding toTerm. Similar toencode/2, can be customised with theEncodercallback andOptions.Optionscan include'indent'to specify number of spaces per level and'max'which loosely limits the width of lists. TheEncoderwill get a'State'argument which contains the'Options'maps merged with other data when recursing through'Term'.format_value/3or variousencode_*functions in this module can be used to help in constructing such callbacks. This is the customisation station. π
> formatter({posix_time, SysTimeSecs}, Encode, State) ->
TimeStr = calendar:system_time_to_rfc3339(SysTimeSecs, [{offset, "Z"}]),
json:format_value(unicode:characters_to_binary(TimeStr), Encode, State);
> formatter(Other, Encode, State) -> json:format_value(Other, Encode, State).
>
> Fun = fun(Value, Encode, State) -> formatter(Value, Encode, State) end.
> Options = #{indent => 4}.
> Term = #{id => 1, time => {posix_time, erlang:system_time(seconds)}}.
>
> io:put_chars(json:format(Term, Fun, Options)).
{
"id": 1,
"time": "2024-05-23T16:07:48Z"
}
ok
format_key_value_list([{term(), term()}], Encode :: formatter(), State :: map()) -> iodata().β format function for lists of key-value pairs as JSON objects. Accepts lists with atom, binary, integer, or float keys. πformat_key_value_list_checked([{term(), term()}], Encoder :: formatter(), State :: map()) -> iodata().β format function for lists of key-value pairs as JSON objects. Accepts lists with atom, binary, integer, or float keys. Verifies that no duplicate keys will be produced in the resulting JSON object. No dupes allowed. π«
Errors
Raises error({duplicate_key, Key}) if there are duplicates.
format_value(Value :: dynamic(), Encode :: formatter(), State :: map()) -> iodata().β default format function used byjson:format/1. Recursively callsEncodeon all the values inValue, and indents objects and lists. It's the recursive queen. π
That's the whole vibe, bestie. This page is brought to you by Ericsson AB, stdlib 8.0.4, and json(3). No date on this footer, but the version is iconic. Periodt. π β¨
π¦ where this page comes from
- ubuntu stonking: erlang-doc 1:29.0.6+dfsg-1 Β· Apache-2.0
- π girlified by deepseek-ai/DeepSeek-V4.1-Flash on : a language model's rewrite of the original, under its terms