Ecosyste.ms: Awesome
An open API service indexing awesome lists of open source software.
https://github.com/potatosalad/erlang-ojson
Ordered JSON (OJSON) - deterministic or stable serialization
https://github.com/potatosalad/erlang-ojson
deterministic elixir erlang hex json ordered rebar3 stable
Last synced: about 4 hours ago
JSON representation
Ordered JSON (OJSON) - deterministic or stable serialization
- Host: GitHub
- URL: https://github.com/potatosalad/erlang-ojson
- Owner: potatosalad
- License: mpl-2.0
- Created: 2017-05-17T21:08:42.000Z (over 7 years ago)
- Default Branch: master
- Last Pushed: 2017-05-17T21:57:28.000Z (over 7 years ago)
- Last Synced: 2024-03-14T18:18:58.801Z (8 months ago)
- Topics: deterministic, elixir, erlang, hex, json, ordered, rebar3, stable
- Language: Erlang
- Size: 113 KB
- Stars: 10
- Watchers: 4
- Forks: 1
- Open Issues: 1
-
Metadata Files:
- Readme: README.md
- Changelog: CHANGELOG.md
- License: LICENSE.md
Awesome Lists containing this project
README
# Ordered JSON (OJSON)
[![Build Status](https://travis-ci.org/potatosalad/erlang-ojson.svg?branch=master)](https://travis-ci.org/potatosalad/erlang-ojson) [![Hex.pm](https://img.shields.io/hexpm/v/ojson.svg)](https://hex.pm/packages/ojson)
Ordered JSON (JSON) is a deterministic or stable JSON encoder and decoder for Erlang and Elixir.
OJSON is similar to projects like [fast-stable-stringify](https://github.com/nickyout/fast-stable-stringify) and [json-stable-stringify](https://github.com/substack/json-stable-stringify) which allows for deterministic serialization of object key order.
Before you say, ["JSON is unordered!"](https://tools.ietf.org/html/rfc7159#section-1), the initial use-case for this library is with cryptographic operations, which rely on stable input for authentication and verification in serialized form. The ordering only applies to the encoding/serialization operations.
Initially based on [devinus/poison](https://github.com/devinus/poison), but rewritten for use as a dependency for Erlang or Elixir projects.
## Installation
If [using Hex](https://hex.pm/), the package can be installed
by adding `ojson` to your list of dependencies in `mix.exs`:```elixir
def deps do
[{:ojson, "~> 1.0.0"}]
end
```If [using rebar3](http://www.rebar3.org/), the package can be installed by adding `ojson` to you list of dependencies in `rebar.config`:
```erlang
{deps, [
{ojson, ".*", {git, "git://github.com/potatosalad/erlang-ojson.git", {branch, "master"}}}
]}.
```The [HexDocs](https://hexdocs.pm) can
be found at [https://hexdocs.pm/ojson](https://hexdocs.pm/ojson).## Usage
##### Basic Usage
_Elixir_
```elixir
iex> OJSON.encode(%{"z" => 1, "a" => 2})
{:ok, "{\"a\":2,\"z\":1}"}iex> OJSON.encode!(%{"z" => 1, "a" => 2})
"{\"a\":2,\"z\":1}"iex> OJSON.encode_to_iodata(%{"z" => 1, "a" => 2})
{:ok, [123, [[34, ["a"], 34], 58, "2"], [[44, [34, ["z"], 34], 58, "1"]], 125]}iex> OJSON.encode_to_iodata!(%{"z" => 1, "a" => 2})
[123, [[34, ["a"], 34], 58, "2"], [[44, [34, ["z"], 34], 58, "1"]], 125]iex> OJSON.decode("{\"a\":2,\"z\":1}")
{:ok, %{"a" => 2, "z" => 1}}iex> OJSON.decode!("{\"a\":2,\"z\":1}")
%{"a" => 2, "z" => 1}
```_Erlang_
```erlang
ojson:encode(#{ <<"z">> => 1, <<"a">> => 2 }).
% {ok, <<"{\"a\":2,\"z\":1}">>}ojson:'encode!'(#{ <<"z">> => 1, <<"a">> => 2 }).
% <<"{\"a\":2,\"z\":1}">>ojson:encode_to_iodata(#{ <<"z">> => 1, <<"a">> => 2 }).
% {ok, [123,[[34,[<<"a">>],34],58,<<"2">>],[[44,[34,[<<"z">>],34],58,<<"1">>]],125]}ojson:'encode_to_iodata!'(#{ <<"z">> => 1, <<"a">> => 2 }).
% [123,[[34,[<<"a">>],34],58,<<"2">>],[[44,[34,[<<"z">>],34],58,<<"1">>]],125]ojson:decode(<<"{\"a\":2,\"z\":1}">>).
% {ok, #{<<"a">> => 2, <<"z">> => 1}}ojson:'decode!'(<<"{\"a\":2,\"z\":1}">>).
% #{<<"a">> => 2, <<"z">> => 1}
```##### Deterministic Example
_Elixir_
```elixir
# Let's first generate a map with 32 key/value pairs:
iex> map = for key <- :lists.seq(0, 32), into: %{}, do: {String.pad_leading(:erlang.integer_to_binary(key, 16), 2, "0"), 0}
%{"10" => 0, "0E" => 0, "14" => 0, "12" => 0, "16" => 0, "07" => 0, "1C" => 0,
"06" => 0, "19" => 0, "13" => 0, "04" => 0, "1E" => 0, "1F" => 0, "11" => 0,
"15" => 0, "17" => 0, "1A" => 0, "0A" => 0, "18" => 0, "0C" => 0, "00" => 0,
"0B" => 0, "09" => 0, "02" => 0, "0D" => 0, "1D" => 0, "20" => 0, "03" => 0,
"0F" => 0, "1B" => 0, "01" => 0, "05" => 0, "08" => 0}# Notice that the key/value pairs are unordered.
# Now let's encode our unordered map into an ordered JSON string:
iex> OJSON.encode!(map)
"{\"00\":0,\"01\":0,\"02\":0,\"03\":0,\"04\":0,\"05\":0,\"06\":0,\"07\":0,\"08\":0,\"09\":0,\"0A\":0,\"0B\":0,\"0C\":0,\"0D\":0,\"0E\":0,\"0F\":0,\"10\":0,\"11\":0,\"12\":0,\"13\":0,\"14\":0,\"15\":0,\"16\":0,\"17\":0,\"18\":0,\"19\":0,\"1A\":0,\"1B\":0,\"1C\":0,\"1D\":0,\"1E\":0,\"1F\":0,\"20\":0}"
```_Erlang_
```erlang
%% Let's first generate a map with 32 key/value pairs:
Map = maps:from_list([{case erlang:integer_to_binary(I, 16) of <> -> <<$0,B>>; B -> B end, 0} || I <- lists:seq(0, 32)]).
% #{<<"10">> => 0,<<"0E">> => 0,<<"14">> => 0,<<"12">> => 0,
% <<"16">> => 0,<<"07">> => 0,<<"1C">> => 0,<<"06">> => 0,
% <<"19">> => 0,<<"13">> => 0,<<"04">> => 0,<<"1E">> => 0,
% <<"1F">> => 0,<<"11">> => 0,<<"15">> => 0,<<"17">> => 0,
% <<"1A">> => 0,<<"0A">> => 0,<<"18">> => 0,<<"0C">> => 0,
% <<"00">> => 0,<<"0B">> => 0,<<"09">> => 0,<<"02">> => 0,
% <<"0D">> => 0,<<"1D">> => 0,<<"20">> => 0,<<"03">> => 0,
% <<"0F">> => 0,<<"1B">> => 0,<<"01">> => 0,<<"05">> => 0,
% <<"08">> => 0}%% Notice that the key/value pairs are unordered.
%% Now let's encode our unordered map into an ordered JSON string:
ojson:'encode!'(Map).
% <<"{\"00\":0,\"01\":0,\"02\":0,\"03\":0,\"04\":0,\"05\":0,\"06\":0,\"07\":0,\"08\":0,\"09\":0,\"0A\":0,\"0B\":0,\"0C\":0,\"0D\":0,\"0E\":0,\"0F\":0,\"10\":0,\"11\":0,\"12\":0,\"13\":0,\"14\":0,\"15\":0,\"16\":0,\"17\":0,\"18\":0,\"19\":0,\"1A\":0,\"1B\":0,\"1C\":0,\"1D\":0,\"1E\":0,\"1F\":0,\"20\":0}">>
```