hairyhum
hairyhum

Reputation: 156

Erlang JSON API data lifecycle

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

Answers (3)

alavrik
alavrik

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

Muzaaya Joshua
Muzaaya Joshua

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":[
{"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).
Now Databases, i dont know what you really want, but, normally, we can write data in a Key Value store , 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

I GIVE CRAP ANSWERS
I GIVE CRAP ANSWERS

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

Related Questions