Search documentation of stdlib

# json (stdlib v8.0.3)

Copy Markdown View Source

A library for encoding and decoding JSON.

This module implements EEP68.

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

## Summary

### Types

array_finish_fun()
array_push_fun()
array_start_fun()
continuation_state()
decode_value()
decoders()
encode_map(Value)
encode_value()

Simple JSON value encodeable with `json:encode/1`.

encoder()
formatter()
from_binary_fun()
object_finish_fun()
object_push_fun()
object_start_fun()

### Functions

decode(Binary)

Parses a JSON value from `Binary`.

decode(Binary, Acc0, Decoders)

Parses a JSON value from `Binary`.

decode_continue/2

Continue parsing a stream of bytes of a JSON value.

decode_start(Binary, Acc, Decoders)

Begin parsing a stream of bytes of a JSON value.

encode(Term)

Generates JSON corresponding to `Term`.

encode(Term, Encoder)

Generates JSON corresponding to `Term`.

encode_atom/2

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

encode_binary(Bin)

Default encoder for binaries as JSON strings used by `json:encode/1`.

encode_binary_escape_all(Bin)

Encoder for binaries as JSON strings producing pure-ASCII JSON.

encode_float(Float)

Default encoder for floats as JSON numbers used by `json:encode/1`.

encode_integer(Integer)

Default encoder for integers as JSON numbers used by `json:encode/1`.

encode_key_value_list(List, Encode)

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

encode_key_value_list_checked(List, Encode)

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

encode_list(List, Encode)

Default encoder for lists as JSON arrays used by `json:encode/1`.

encode_map(Map, Encode)

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

encode_map_checked(Map, Encode)

Encoder for maps as JSON objects.

encode_value(Value, Encode)

Default encoder used by `json:encode/1`.

format(Term)

Generates formatted JSON corresponding to `Term`.

format/2

Generates formatted JSON corresponding to `Term`.

format(Term, Encoder, Options)

Generates formatted JSON corresponding to `Term`.

format_key_value_list/3

Format function for lists of key-value pairs as JSON objects.

format_key_value_list_checked(KVList, UserEnc, State)

Format function for lists of key-value pairs as JSON objects.

format_value(Value, Encode, State)

Default format function used by `json:format/1`.

## Types

# array_finish_fun()

(since OTP 27.0)

    -type array_finish_fun() :: fun((ArrayAcc :: dynamic(), OldAcc :: dynamic()) -> {dynamic(), dynamic()}).

# array_push_fun()

(since OTP 27.0)

    -type array_push_fun() :: fun((Value :: dynamic(), Acc :: dynamic()) -> NewAcc :: dynamic()).

# array_start_fun()

(since OTP 27.0)

    -type array_start_fun() :: fun((Acc :: dynamic()) -> ArrayAcc :: dynamic()).

# continuation_state()

(since OTP 27.0)

    -opaque continuation_state()

# decode_value()

(since OTP 27.0)

    -type decode_value() ::
              integer() |
              float() |
              boolean() |
              null |
              binary() |
              [decode_value()] |
              #{binary() => decode_value()}.

# decoders()

(since OTP 27.0)

    -type 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)

(not exported) (since OTP 27.0)

    -type encode_map(Value) :: #{binary() | atom() | integer() => Value}.

# encode_value()

(since OTP 27.0)

    -type encode_value() ::
              integer() |
              float() |
              boolean() |
              null |
              binary() |
              atom() |
              [encode_value()] |
              encode_map(encode_value()).

Simple JSON value encodeable with `json:encode/1`.

# encoder()

(since OTP 27.0)

    -type encoder() :: fun((dynamic(), encoder()) -> iodata()).

# formatter()

(since OTP 27.0)

    -type formatter() :: fun((Term :: dynamic(), Encoder :: formatter(), State :: map()) -> iodata()).

# from_binary_fun()

(since OTP 27.0)

    -type from_binary_fun() :: fun((binary()) -> dynamic()).

# object_finish_fun()

(since OTP 27.0)

    -type object_finish_fun() ::
              fun((ObjectAcc :: dynamic(), OldAcc :: dynamic()) -> {dynamic(), dynamic()}).

# object_push_fun()

(since OTP 27.0)

    -type object_push_fun() ::
              fun((Key :: dynamic(), Value :: dynamic(), Acc :: dynamic()) -> NewAcc :: dynamic()).

# object_start_fun()

(since OTP 27.0)

    -type object_start_fun() :: fun((Acc :: dynamic()) -> ObjectAcc :: dynamic()).

## Functions

# decode(Binary)

(since OTP 27.0)

    -spec 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, Acc0, Decoders)

(since OTP 27.0)

    -spec 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/2

(since OTP 27.0)

    -spec 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, Acc, Decoders)

(since OTP 27.0)

    -spec 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(Term)

(since OTP 27.0)

    -spec 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(Term, Encoder)

(since OTP 27.0)

    -spec 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/2

(since OTP 27.0)

    -spec 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(Bin)

(since OTP 27.0)

    -spec 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(Bin)

(since OTP 27.0)

    -spec 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)

(since OTP 27.0)

    -spec encode_float(float()) -> iodata().

Default encoder for floats as JSON numbers used by `json:encode/1`.

# encode_integer(Integer)

(since OTP 27.0)

    -spec encode_integer(integer()) -> iodata().

Default encoder for integers as JSON numbers used by `json:encode/1`.

# encode_key_value_list(List, Encode)

(since OTP 27.0)

    -spec 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(List, Encode)

(since OTP 27.0)

    -spec 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, Encode)

(since OTP 27.0)

    -spec encode_list(list(), encoder()) -> iodata().

Default encoder for lists as JSON arrays used by `json:encode/1`.

# encode_map(Map, Encode)

(since OTP 27.0)

    -spec 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, Encode)

(since OTP 27.0)

    -spec 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(Value, Encode)

(since OTP 27.0)

    -spec encode_value(dynamic(), encoder()) -> iodata().

Default encoder used by `json:encode/1`.

Recursively calls `Encode` on all the values in `Value`.

# format(Term)

(since OTP 27.1)

    -spec 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/2

(since OTP 27.1)

    -spec 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, Encoder, Options)

(since OTP 27.1)

    -spec 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/3

(since OTP 27.2)

    -spec 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(KVList, UserEnc, State)

(since OTP 27.2)

    -spec 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, Encode, State)

(since OTP 27.1)

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