json(3)

NAME
json - A library for encoding and decoding JSON.

DESCRIPTION

This module implements EEP68.

Both encoder and decoder fully conform to RFC 8259 and ECMA 404 standards. The decoder is tested using JSONTestSuite.

DATA TYPES

array_finish_fun() :: fun((ArrayAcc :: dynamic(), OldAcc :: dynamic()) -> {dynamic(), dynamic()}).
array_push_fun() :: fun((Value :: dynamic(), Acc :: dynamic()) -> NewAcc :: dynamic()).
array_start_fun() :: fun((Acc :: dynamic()) -> ArrayAcc :: dynamic()).
-opaque continuation_state()
decode_value() :: integer() | float() | boolean() | null | binary() | [decode_value()] | #{binary() => decode_value()}.
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) :: #{binary() | atom() | integer() => Value}.
encode_value() :: integer() | float() | boolean() | null | binary() | atom() | [encode_value()] | encode_map(encode_value()).

    Simple JSON value encodeable with json:encode/1.
encoder() :: fun((dynamic(), encoder()) -> iodata()).
formatter() :: fun((Term :: dynamic(), Encoder :: formatter(), State :: map()) -> iodata()).
from_binary_fun() :: fun((binary()) -> dynamic()).
object_finish_fun() :: fun((ObjectAcc :: dynamic(), OldAcc :: dynamic()) -> {dynamic(), dynamic()}).
object_push_fun() :: fun((Key :: dynamic(), Value :: dynamic(), Acc :: dynamic()) -> NewAcc :: dynamic()).
object_start_fun() :: fun((Acc :: dynamic()) -> ObjectAcc :: dynamic()).

FUNCTIONS

decode(binary()) -> decode_value().

    Parses a JSON value from Binary.

    Supports basic data mapping:

        **JSON** | **Erlang**
        Number | `integer() | float()`
        Boolean | `true | false`
        Null | null
        String | binary()
        Object | #{binary() => _}

  Errors

    • error(unexpected_end) if Binary contains incomplete JSON value

    • error({invalid_byte, Byte}) if Binary contains unexpected byte or invalid UTF-8 byte

    • error({unexpected_sequence, Bytes}) if Binary contains invalid UTF-8 escape

  Example

    > json:decode(<<"{\"foo\": 1}">>).
    #{<<"foo">> => 1}
decode(binary(), dynamic(), decoders()) -> {Result :: dynamic(), Acc :: dynamic(), binary()}.

    Parses a JSON value from Binary.

    Similar to decode/1 except the decoding process can be customized with the callbacks specified in Decoders. The callbacks will use the Acc value as the initial accumulator.

    Any leftover, unparsed data in Binary will be returned.

  Default callbacks

All callbacks are optional. If not provided, they will fall back to 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 atom null

  Errors

    • error({invalid_byte, Byte}) if Binary contains unexpected byte or invalid UTF-8 byte

    • error({unexpected_sequence, Bytes}) if Binary contains invalid UTF-8 escape

    • error(unexpected_end) if Binary contains 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(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(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 returns when a complete JSON value can be parsed or returns {continue, State} for incomplete data, the State can be fed to the decode_continue/2 function when more data is available.
encode(encode_value()) -> iodata().

    Generates JSON corresponding to Term.

    Supports basic data mapping:

        **Erlang** | **JSON**
        `integer() | float()` | Number
        `true | false ` | Boolean
        null | Null
        binary() | String
        atom() | String
        list() | Array
        #{binary() => _} | Object
        #{atom() => _} | Object
        #{integer() => _} | Object

    This is equivalent to encode(Term, fun json:encode_value/2).

  Examples

    > iolist_to_binary(json:encode(#{foo => <<"bar">>})).
    <<"{\"foo\":\"bar\"}">>
encode(dynamic(), encoder()) -> iodata().

    Generates JSON corresponding to Term.

    Can be customised with the Encoder callback. The 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(atom(), encoder()) -> iodata().

    Default encoder for atoms used by json:encode/1.

    Encodes the atom null as JSON null, atoms true and false as JSON booleans, and everything else as JSON strings calling the Encode callback with the corresponding binary.
encode_binary(binary()) -> iodata().

    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(binary()) -> iodata().

    Encoder for binaries as JSON strings producing 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(float()) -> iodata().

    Default encoder for floats as JSON numbers used by json:encode/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().

    Encoder for lists of key-value pairs as JSON objects.

    Accepts lists with atom, binary, integer, or float keys.
encode_key_value_list_checked([{term(), term()}], encoder()) -> iodata().

    Encoder 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.

  Errors

Raises error({duplicate_key, Key}) if there are duplicates.
encode_list(list(), encoder()) -> iodata().

    Default encoder for lists as JSON arrays used by json:encode/1.
encode_map(encode_map(dynamic()), encoder()) -> iodata().

    Default encoder for maps as JSON objects used by json:encode/1.

    Accepts maps with atom, binary, integer, or float keys.
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.

  Errors

Raises error({duplicate_key, Key}) if there are duplicates.
encode_value(dynamic(), encoder()) -> iodata().

    Default encoder used by json:encode/1.

    Recursively calls Encode on all the values in Value.
format(Term :: encode_value()) -> iodata().

    Generates formatted JSON corresponding to Term.

    Similiar to encode/1 but with added whitespaces for formatting.

        > 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 to Term.

    Equivalent to format(Term, fun json:format_value/3, Options) or format(Term, Encoder, #{})
format(Term :: dynamic(), Encoder :: formatter(), Options :: map()) -> iodata().

    Generates formatted JSON corresponding to Term.

    Similar to encode/2, can be customised with the Encoder callback and Options.

    Options can include 'indent' to specify number of spaces per level and 'max' which loosely limits the width of lists.

    The Encoder will get a 'State' argument which contains the 'Options' maps merged with other data when recursing through 'Term'.

    format_value/3 or various encode_* functions in this module can be used to help in constructing such callbacks.

        > 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.

  Errors

Raises error({duplicate_key, Key}) if there are duplicates.
format_value(Value :: dynamic(), Encode :: formatter(), State :: map()) -> iodata().

    Default format function used by json:format/1.

    Recursively calls Encode on all the values in Value, and indents objects and lists.