All Projects → EduardSergeev → jsonrec

EduardSergeev / jsonrec

Licence: MIT license
JSON parser/encoder "type spec"-based code-generator

Programming Languages

erlang
1774 projects

Projects that are alternatives of or similar to jsonrec

doku
fn(Code) -> Docs
Stars: ✭ 65 (+400%)
Mutual labels:  serialization
succinct-binary
Succinct binary serialization
Stars: ✭ 16 (+23.08%)
Mutual labels:  serialization
HashStablePack
Serialization code generator for QUICK struct content comparison
Stars: ✭ 94 (+623.08%)
Mutual labels:  serialization
drf-action-serializer
A serializer for the Django Rest Framework that supports per-action serialization of fields.
Stars: ✭ 48 (+269.23%)
Mutual labels:  serialization
vue-query-builder
A Vue-Query-Builder
Stars: ✭ 71 (+446.15%)
Mutual labels:  serialization
ikeapack
Compact data serializer/packer written in Go, intended to produce a cross-language usable format.
Stars: ✭ 18 (+38.46%)
Mutual labels:  serialization
VSerializer
A library to serialize and deserialize objects with minimum memory usage.
Stars: ✭ 25 (+92.31%)
Mutual labels:  serialization
use-query-string
🆙 A React hook that serializes state into the URL query string
Stars: ✭ 50 (+284.62%)
Mutual labels:  serialization
MetaCPP
C++ Reflection & Serialization using Clang's LibTooling
Stars: ✭ 44 (+238.46%)
Mutual labels:  serialization
json-strictify
Safely serialize a value to JSON without unintended loss of data or going into an infinite loop due to circular references.
Stars: ✭ 14 (+7.69%)
Mutual labels:  serialization
baltar
Example graphics editor using MobX
Stars: ✭ 42 (+223.08%)
Mutual labels:  serialization
desert
Deserialize to objects while staying DRY
Stars: ✭ 136 (+946.15%)
Mutual labels:  serialization
SwiftCBOR
A CBOR implementation for Swift
Stars: ✭ 95 (+630.77%)
Mutual labels:  serialization
kafka-protobuf-serde
Serializer/Deserializer for Kafka to serialize/deserialize Protocol Buffers messages
Stars: ✭ 52 (+300%)
Mutual labels:  serialization
sirdez
Glorious Binary Serialization and Deserialization for TypeScript.
Stars: ✭ 20 (+53.85%)
Mutual labels:  serialization
dataclasses-jsonschema
JSON schema generation from dataclasses
Stars: ✭ 145 (+1015.38%)
Mutual labels:  serialization
typical
Data interchange with algebraic data types.
Stars: ✭ 114 (+776.92%)
Mutual labels:  serialization
serialize-json
A serialize algorithm for JSON
Stars: ✭ 22 (+69.23%)
Mutual labels:  serialization
tyson
A TypeScript serialization/deserialization library to convert objects to/from JSON
Stars: ✭ 25 (+92.31%)
Mutual labels:  serialization
JsonFormatter
Easy, Fast and Lightweight Json Formatter. (Serializer and Deserializer)
Stars: ✭ 26 (+100%)
Mutual labels:  serialization

Jsonrec

Build Status

Overview

Jsonrec is a yet another JSON encode/decode library written in Erlang. Even though one cannot say there is a lack of JSON libraries written in Erlang none of existing ones, to my knowledge, provides direct, seamless mapping between Erlang records and JSON (while jsonrec does). This library uses compile-time code generation to produce JSON encoding and decoding code based on record type annotations.

How it works

Given Erlang record definition with type annotation (fields can be of any JSON-compatible types including user-defined types, lists and nested records of arbitrary depth) jsonrec produces the body for "encode" and "decode" function (with a help of meta library which in tern uses Erlang parse_transform/2 function for source manipulation). The resulting functions can then be used as normal Erlang function.

Benefits of jsonrec

  • Resulting functions consume and produce Erlang records which is much more convenient and safer (bug-free) to use then proplists or other weakly-typed structures (Erlang compiler and, optionally, Dialyzer can detects bugs and discrepancies at compile time)
  • Encoding/decoding functions are tailored in compile-time using type annotations so the resulting code can be much more efficient (in comparison to generic JSON parser/generator). In fact initial tests show that jsonrec is in majority cases faster then any existing purely Erlang-based JSON library, for both encoding and decoding. C-based parsers, like ejson, are still understandably faster but this may change once critical parsers code is rewriten using NIF.

Quickstart examples

Note: the code below can be found in example/readme.erl file.

To use jsonrec simply add the following header:

-include_lib("jsonrec/include/jsonrec.hrl").

Then, lets say we have the following set of records which we want to generate serialization code for:

-type country() :: 'AU' | 'RU' | 'UK' | 'US'.
-record(address,
        {line1 :: string(),
         line2 = "" :: string(),
         line3 = "" :: string(),
         country :: country(),
         zip :: string()}).

-type phone_kind() :: work | home | mobile.
-record(phone,
        {kind = mobile :: phone_kind(),
         number :: string(),
         is_prefered :: boolean()}).

-record(person,
        {id :: integer(),
         first_name :: string(),
         last_name :: string(),
         address = unknown :: #address{},
         phones = [] :: [#phone{}]}).

Then JSON encoding function for #person{} can be coded with the following line:

encode(#person{} = Rec) ->
    ?encode_gen(#person{}, Rec).

While JSON decoding function (from binary() input into #person{} record):

decode(Bin) ->
    ?decode_gen(#person{}, Bin).

Now we can test if it works as expected:

1> rr(readme).
[address,person,phone]
2> A = #address{line1 = "John Smith", line2 = "Elm Street", country = 'US'},                          
2> Ph1 = #phone{number = "123456", kind = home},                                                      
2> Ph2 = #phone{number = "0404123456", is_prefered = true},                                           
2> Rec = #person{id = 42, first_name = "John", last_name = "Smith", address = A, phones = [Ph1, Ph2]}.
#person{id = 42,first_name = "John",last_name = "Smith",
        address = #address{line1 = "John Smith",
                           line2 = "Elm Street",line3 = [],country = 'US',
                           zip = undefined},
        phones = [#phone{kind = home,number = "123456",
                         is_prefered = undefined},
                  #phone{kind = mobile,number = "0404123456",
                         is_prefered = true}]}
3> IoList = readme:encode(Rec),                                                                       
3> io:format("~s~n", [IoList]).                                                                       
{"id":42,"first_name":"John","last_name":"Smith","address":{"line1":"John Smith","line2":"Elm Street","line3":"","country":"US"},"phones":[{"kind":"home","number":"123456"},{"kind":"mobile","number":"0404123456","is_prefered":true}]}
ok
4> Bin = list_to_binary(IoList),                                                                      
4> {ok, Restored} = readme:decode(Bin).
{ok,#person{id = 42,first_name = "John",last_name = "Smith",
            address = #address{line1 = "John Smith",
                               line2 = "Elm Street",line3 = [],country = 'US',
                               zip = undefined},
            phones = [#phone{kind = home,number = "123456",
                             is_prefered = undefined},
                      #phone{kind = mobile,number = "0404123456",
                             is_prefered = true}]}}
5> Rec == Restored.                    
true 

Decoding function is quite flexible: fields can be present in JSON in a different order or some can be omitted (in which case either undefined or "default" value is set in the resulting record):

6> readme:decode(<<"{}">>).                                                                           
{ok,#person{id = undefined,first_name = undefined,
            last_name = undefined,address = unknown,phones = []}}

While attempt to pass invalid JSON will result in parsing error:

7> readme:decode(<<"}">>). 
{error,{expected,<<"{">>,at,<<"}">>}}

Supported types

  • The following standard types are currently supported (corresponding JSON types mapping is also given):
    • boolean() <-> true | false
    • integer() <-> number
    • float() <-> number
    • binary() <-> string
    • string() <-> string
    • atom() <-> string
    • undefined <-> omitted field or null
  • User defined types (in the form -type some_type() :: type_def)
  • list(Type) <-> array where Type can be any supported type
  • Union of types (some_type() | another_type() | more_types) Note: these types can be problematic especially for decoding (even though binary() | integer() is not a problem, how can you decode #rec1{} | #rec2{} type?) - such cases may require some manual coding (see example below)
  • record <-> object - where every field of the record is mapped according to its type. Default values specified in records are also handled. undefined value of any field currently results in field being omitted in generated JSON.
  • any() (or missing type annotation) - transparent type mapping: the value of the field simply inserted into generated JSON (so it better be of iolist() type) on encoding while binary() part of the corresponding JSON input is assigned to this field on decoding without any processing. This type can be used if custom decoding/encoding is required (See decode_options() type description below).

Detailed library description

TODO

Current state of the library

As of today the library is in "experimental" stage: it was not thoroughly tested and is still in active development.

Note that the project description data, including the texts, logos, images, and/or trademarks, for each open source project belongs to its rightful owner. If you wish to add or remove any projects, please contact us at [email protected].