Reputation: 156
What is the best practices of using Erlang in JSON API's? I mean how do you deal with JSON - Logic - Database - Logic - JSON lifecycle. What data structures, tools and techniques are you using in Erlang apps?
Upvotes: 3
Views: 2430
Reputation: 2161
For working with JSON, I use mochijson2 and Erlson.
mochijson2
is a part of the mochiweb project. It is a stable, battle-tested, pure Erlang implementation with flexible JSON parsing and generation APIs.
Erlson provides a nice dictionary syntax for Erlang which is especially handy when working with JSON. For example:
#[
foo = 1,
bar = "some string",
nested = #[i = 1, b = true]
]
In addition, Erlson comes with erlson:to_json
and erlson:from_json
functions for converting between Erlson and JSON using mochiweb2
.
(disclaimer: I'm the author of Erlson)
Upvotes: 5
Reputation: 7836
Your question is bigger than the answers received so far. However, for Manipulating JSON, they have all told you about mochijson.erl
, mochijson2.erl
all of which come with mochiweb
HTTP Library. To use them, a JSON Object is represented as a Struct
Object like this:
In JSON
{"FirstName": "Joshua", "Surname": "Muzaaya"}
In Erlang
{struct,[{<<"FirstName">>,<<"Joshua">>},{<<"Surname">>,<<"Muzaaya">>}]}
To Parse to and Fro:
JSON_DATA = {"students":[Now Databases, i dont know what you really want, but, normally, we can write data in a Key Value store ,
{"student_number":45,
"details":[{"FirstName": "Joshua", "Surname": "Muzaaya"} ] } ]}
From JSON to Erlang
$> mochijson2:decode(JSON_DATA). {struct,[{<<"students">>, [{struct,[{<<"student_number">>,45}, {<<"details">>, [{struct,[{<<"FirstName">>,<<"Joshua">>}, {<<"Surname">>,<<"Muzaaya">>}]}]}]}]}]}
From Erlang to JSON
$> mochijson2:encode(StructObject).
Mnesia
, or CouchDB
via a RESTFUL
access API. I have written a Couchbase Single Server
Client in Erlang. Here are some of the functions inside: create_database(ServerDomain,DBName)-> try ibrowse:send_req(ServerDomain ++ DBName,[{"Content-Type",
"application/json"}],put,[]) of
{ok,_,_,Result} -> case proplists:get_value(<<"ok">>,element(2,mochijson2:decode(Result
))) of undefined -> {error,failed}; _ -> ok end; Any -> {error,Any} catch EE:EE2 -> {error,{EE,EE2}} end.
delete_database(ServerDomain,DBName)-> try ibrowse:send_req(ServerDomain ++ DBName,[{"Content-Type","application/json"}],delete,[]) of {ok,_,_,Result} -> case proplists:get_value(<<"ok">>,element(2,mochijson2:decode(Result))) of undefined -> {error,failed}; _ -> ok end; Any -> {error,Any} catch EE:EE2 -> {error,{EE,EE2}} end.
%% read/3 ::= Struct
read(ServerDomain,DBName,DocId)-> try ibrowse:send_req(ServerDomain ++ DBName ++ "/" ++ DocId,[{"Content-Type","application/json"}],get,[]) of
{ok,_,_,Result} -> mochijson2:decode(Result);
Any -> {error,Any} catch EE:EE2 -> {error,{EE,EE2}} end.
%% write/3 ::= [{id,Id::string()},{rev,Rev::string()}]
write(ServerDomain,DBName,DocStruct)-> try ibrowse:send_req(ServerDomain ++ DBName,[{"Content-Type","application/json"}],post,lists:flatten(mochijson:encode(DocStruct))) of
{ok,_,_,Result} -> E = element(2,mochijson2:decode(Result)), case {proplists:get_value(<<"id">>,E),proplists:get_value(<<"rev">>,E)} of {undefined,_} -> {error,E}; {_,undefined} -> {error,E}; {Id,Rev} -> [{id,binary_to_list(Id)},{rev,binary_to_list(Rev)}]
end;
Any -> {error,Any} catch EE:EE2 -> {error,{EE,EE2}} end.
%% remember to specify the '_rev' of recent copy when updating %% update/4 ::= [{id,Id::string()},{rev,Rev::string()}] update(ServerDomain,DBName,DocId,DocStruct)-> try ibrowse:send_req(ServerDomain ++ DBName ++ "/" ++ DocId,[{"Content-Type","application/json"}],put,lists:flatten(mochijson:encode(DocStruct))) of
{ok,_,_,Result} -> E = element(2,mochijson2:decode(Result)), case {proplists:get_value(<<"id">>,E),proplists:get_value(<<"rev">>,E)} of {undefined,_} -> {error,E}; {_,undefined} -> {error,E}; {Id,Rev} -> [{id,binary_to_list(Id)},{rev,binary_to_list(Rev)}]
end;
Any -> {error,Any} catch EE:EE2 -> {error,{EE,EE2}} end.
%% you need to provide the '_rev' of current copy %% of doc to be deleted
delete(ServerDomain,DBName,DocId,Rev)-> try ibrowse:send_req(ServerDomain ++ DBName ++ "/" ++ DocId ++ "?rev=" ++ Rev,[{"Content-Type","application/json"}],delete,[]) of
{ok,_,_,Result} -> E = element(2,mochijson2:decode(Result)), case {proplists:get_value(<<"id">>,E),proplists:get_value(<<"ok">>,E)} of {undefined,_} -> {error,E}; {_,undefined} -> {error,E}; {_Id,_} -> ok
end;
Any -> {error,Any} catch EE:EE2 -> {error,{EE,EE2}} end.
random(ServerDomain,Count) when is_integer(Count)-> try ibrowse:send_req(ServerDomain ++ "_uuids?count=" ++ integer_to_list(Count),[{"Content-Type","application/json"}],get,[]) of {ok,_,_,Result} -> [binary_to_list(Z) || Z <- proplists:get_value(<<"uuids">>,element(2,mochijson2:decode(Result)))]; Any -> {error,Any} catch EE:EE2 -> {error,{EE,EE2}} end.
So, perhaps try breaking down your question. Otherwise, you can see above that i am playing alot with JSON. To use the methods abpve, first make user ibrowse
is running.
Upvotes: 1
Reputation: 18879
There are two tools I tend to use for JSON in Erlang: jsx
and jiffy
. Check them both as they have slightly different properties w.r.t flexibility and speed.
The major problem is that Erlang has no built-in dictionary type. Hence, JSON objects are often represented as a property list, i.e.,
{ a : 10,
b : 20 }
is represented as a list of tuples:
[{a, 10}, {b, 20}]
and this is the major thing to look out for. It also means that one should probably avoid using JSON as the internal representation format as much as possible since it is unwieldy to work with in the long run.
Upvotes: 7