README.md

![Test](https://github.com/zotonic/jsxrecord/workflows/Test/badge.svg)

# JSON encoding with records and 'null'/'undefined' mapping

This is a wrapper around `jsx` to handle encoding and decoding of Erlang records.

## JSON null handling

To ease the interop between Erlang and JSON the 'null' handling is changed:

    Erlang    ->    JSON     ->     Erlang

    undefined       null            undefined
    null            null            undefined


## How to use

Before records can be encoded or decoded the record definitions need to be loaded.

After the definitions are loaded then all encoding/decoding is done transparently.

### Loading record definitions

The record definitions are loaded from modules and compiled into a runtime loaded module
containing all field names and default values.

To add record definitions from `mymodule`

    ok = jsxrecord:load_records( [ mymodule ]).

To see the current record definitions:

    jsxrecord:record_defs()

This returns a map with all known record definitions.

### Encoding/decoding records

Let's assume the following record definition has been loaded:

    -record(test, { a = 1, b = 2, c }).

This can now be encoded with:

    jsxrecord:encode( #test{} ).

The resulting JSON is:

    {"_record":"test","a":1,"b":2,"c":null}

Decoding returns the `#test{}`:

    #test{} = jsxrecord:decode(<<"{\"_record\":\"test\",\"a\":1,\"b\":2,\"c\":null}">>).

Defaults are automatically added for fields missing in the JSON:

    #test{ a = 1, b = 2, c = undefined } = jsxrecord:decode(<<"{\"_record\":\"test\"}">>).
    
### Encoding and decoding datetime and timestamp tuples

Datetime tuples are assumed to be in UTC, and are converted into an ISO8601 string:

    <<"\"2008-12-10T13:30:00Z\"">> = jsxrecord:encode({{2008, 12, 10}, {13, 30, 0}})
    
They are converted back into a datetime tuple:
    
    {{2008, 12, 10}, {13, 30, 0}} = jsxrecord:decode(<<"\"2008-12-10T13:30:00Z\"">>)
    
Erlang timestamp tuples are also converted into an ISO8601 string, but with added precision:

    <<"\"2020-06-12T14:00:11.571Z\"">> = jsxrecord:encode({1591,970411,571321})
    
A little bit of precision is lost when converting it back to a timestamp tuple:

    {1591,970411,571000} = jsxrecord:decode(<<"\"2020-06-12T14:00:11.571Z\"">>)
    

## Configuration

Set the application env `jsxrecord.record_modules` to a list of modules whose records need to
be loaded on first use of the encoder or decoder.


## Performance

The input of encode and the output of decode are parsed and expanded.
This makes the encoder and decoder slower than pure `jsx`.
Though the difference shouldn't be too bad in normal usage.