JSON Serialization Library for Erlang

    Since we are very actively using opensource solutions in our activities, the reverse process is quite natural - publishing libraries and components created in our company under free licenses.

    This time we are publishing a JSON serialization library of Erlang data types, authorship si14 under the BSD 2-clause license. Those projects for which this library is written are not ready yet (wait for the announcements by the fall), but the library has already become completely independent and can be used in many other cases. Traditionally, we look forward to cooperation in improvement, we will hear with interest about the application in other projects.

    In the wilds of Erlang

    Unlike many dynamic languages, Erlang has optional type annotations for functions and records. At the moment, they are used by at least 3 utilities: edoc (generates documentation from sources; an example of the resulting documentation can be seen, for example, here ), more importantly, dialyzer (analyzes existing type information and reports types mismatch errors, including declared inconsistencies and inferred types) and PropEr (a system for automatically generating tests based on type information and declaratively set properties of functions). The use of these declarations has become the rule of good form, so almost all quality projects on Erlang have them. Is it possible to use type information elsewhere?

    Jane

    In the process of developing one of the projects, the idea came up: why not use existing type information directly in JS (for example, to render forms or validate data)? A blitz-survey of familiar developers confirmed that the idea is "hanging in the air", but there is no standard solution. Then JANE appeared: an attempt to describe a standard for coding information about records using JSON, which is quite convenient to work with from JS. JANE is especially well combined with BERT , allowing you to work almost transparently in JS with Erlang terms.

    Format and current implementation

    The current format implementation is an executable escript that takes paths to .hrl files with descriptions of records and writes the resulting .json files to the priv / records folder. Each definition of a record in a file is encoded as an element of a top-level dictionary with a key equal to the name of a record and a dictionary describing a given record as a value.
    The description of a specific record is a dictionary with the name of the field as a key and the description of this field as a value.
    The field description is a dictionary with the required type key containing the type specification, and the optional default key specified if the default value is specified for the field in the record specification.
    A type specification is a dictionary with a key equal to the type name and a value equal to the list of type arguments (which may also contain type specifications).
    By default, all field types in records are defined as union of their given type and atom undefined. This is not always convenient, so the current implementation accepts the ignore_undefined parameter, ignoring undefined if it exists.
    An example of using rebar as a post-compile hook:
    {post_hooks, [{'compile', './priv/recordparser ignore_undefined include/test.hrl'}]}.

    Examples

    Record definition:
    
    -record(params_ping, {host :: nonempty_string()}).
    -record(params_tcp, {host :: list(atom()),
                         port = 80 :: pos_integer(),
                         timeout :: pos_integer()}).
    

    Translation result in .json (with ignore_undefined):
    
    {
        "params_ping": {
            "host": {
                "type": {
                    "nonempty_string": []
                }
            }
        },
        "params_tcp": {
            "host": {
                "type": {
                    "list": [
                        {
                            "atom": []
                        }
                    ]
                }
            },
            "port": {
                "type": {
                    "pos_integer": []
                },
                "default": 80
            },
            "timeout": {
                "type": {
                    "pos_integer": []
                }
            }
        }
    }
    

    The same, but without ignore_undefined:
    
    {
        "params_ping": {
            "host": {
                "type": {
                    "union": [
                        {
                            "atom": [
                                "undefined"
                            ]
                        },
                        {
                            "nonempty_string": []
                        }
                    ]
                }
            }
        },
        "params_tcp": {
            "host": {
                "type": {
                    "union": [
                        {
                            "atom": [
                                "undefined"
                            ]
                        },
                        {
                            "nonempty_string": []
                        }
                    ]
                }
            },
            "port": {
                "type": {
                    "pos_integer": []
                },
                "default": 80
            },
            "timeout": {
                "type": {
                    "union": [
                        {
                            "atom": [
                                "undefined"
                            ]
                        },
                        {
                            "pos_integer": []
                        }
                    ]
                }
            }
        }
    }
    


    Links and people

    The library code in our Github repository: github.com/selectel/jane
    Author of the library: si14 .
    Traditionally, thanks akme for agreeing to the BSD-license.

    Also popular now: