# `json`
[🔗](https://github.com/erlang/otp/blob/OTP-28.5/lib/stdlib/src/json.erl#L23)

A library for encoding and decoding JSON.

This module implements [EEP68](https://github.com/erlang/eep/blob/master/eeps/eep-0068.md).

Both encoder and decoder fully conform to
[RFC 8259](https://tools.ietf.org/html/rfc8259) and
[ECMA 404](https://ecma-international.org/publications-and-standards/standards/ecma-404/)
standards. The decoder is tested using [JSONTestSuite](https://github.com/nst/JSONTestSuite).

# `array_finish_fun`
*since OTP 27.0* 

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

# `array_push_fun`
*since OTP 27.0* 

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

# `array_start_fun`
*since OTP 27.0* 

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

# `continuation_state`
*since OTP 27.0* 

```elixir
-opaque continuation_state() :: tuple().
```

# `decode_value`
*since OTP 27.0* 

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

# `decoders`
*since OTP 27.0* 

```elixir
-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`
*not exported* *since OTP 27.0* 

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

# `encode_value`
*since OTP 27.0* 

```elixir
-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* 

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

# `formatter`
*since OTP 27.0* 

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

# `from_binary_fun`
*since OTP 27.0* 

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

# `object_finish_fun`
*since OTP 27.0* 

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

# `object_push_fun`
*since OTP 27.0* 

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

# `object_start_fun`
*since OTP 27.0* 

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

# `decode`
*since OTP 27.0* 

```elixir
-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

```erlang
> json:decode(<<"{\"foo\": 1}">>).
#{<<"foo">> => 1}
```

# `decode`
*since OTP 27.0* 

```elixir
-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:

```erlang
> 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`
*since OTP 27.0* 

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

```erlang
> {continue, State} = json:decode_start(<<"{\"foo\":">>, ok, #{}).
> json:decode_continue(<<"1}">>, State).
{#{foo => 1},ok,<<>>}
```
```erlang
> {continue, State} = json:decode_start(<<"123">>, ok, #{}).
> json:decode_continue(end_of_input, State).
{123,ok,<<>>}
```

# `decode_start`
*since OTP 27.0* 

```elixir
-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`
*since OTP 27.0* 

```elixir
-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

```erlang
> iolist_to_binary(json:encode(#{foo => <<"bar">>})).
<<"{\"foo\":\"bar\"}">>
```

# `encode`
*since OTP 27.0* 

```elixir
-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:

```erlang
> 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`
*since OTP 27.0* 

```elixir
-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`
*since OTP 27.0* 

```elixir
-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`
*since OTP 27.0* 

```elixir
-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`
*since OTP 27.0* 

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

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

# `encode_integer`
*since OTP 27.0* 

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

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

# `encode_key_value_list`
*since OTP 27.0* 

```elixir
-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`
*since OTP 27.0* 

```elixir
-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`
*since OTP 27.0* 

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

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

# `encode_map`
*since OTP 27.0* 

```elixir
-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`
*since OTP 27.0* 

```elixir
-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`
*since OTP 27.0* 

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

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

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

# `format`
*since OTP 27.1* 

```elixir
-spec format(Term :: encode_value()) -> iodata().
```

Generates formatted JSON corresponding to `Term`.

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

```erlang
> io:put_chars(json:format(#{foo => <<"bar">>, baz => 52})).
{
  "baz": 52,
  "foo": "bar"
}
ok
```

# `format`
*since OTP 27.1* 

```elixir
-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`
*since OTP 27.1* 

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

```erlang
> 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`
*since OTP 27.2* 

```elixir
-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`
*since OTP 27.2* 

```elixir
-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`
*since OTP 27.1* 

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

---

*Consult [api-reference.md](api-reference.md) for complete listing*
