[erlang-questions] Best way to send JSON from erlang to the browser and back

Joe Armstrong erlang@REDACTED
Fri Nov 25 16:02:00 CET 2011


I have the following problem:

I have  complex data structure that I want to send back and forward
between Erlang and a browser - what's the best way to do this?

This should be very simple - but the simplest solution I have found is
not entirely obvious. So I was wondering if this is the
best solution, and welcome any suggestions for improvement.

The problem is subject to the following constraints:

   1) I want the data structure to be the same after it has been on
      a "round-trip" from erlang -> browser -> erlang

   2) I want to use publicly available libraries that are in-use and
      maintained.

Here's the solution I use at the moment. I've chosen JSON for data
transport,
jquery in the browser, the Google chrome browser, and mochiweb.

(( is their a better choice - should I use something other than JSON for
the encoding, if so what,
Bert?, something else???)


Step 1
======

In the browser I request data from Erlang

I make a button in html with button id="b">click</button> and hook an event
onto it with

jquery:

    $("#b").click(test_json);

    function test_json(){
    $.ajax({url:"get_term",
    dataType:'json',
    success:function(x){
handle(x);
}
   });
    };

When I click the button a "get_term" messages is sent to an erlang mochiweb
server.

Step 2
======

I make a mochiweb sevrer to reply, which looks like this:

start_server() ->
    mochiweb_http:start([{name,?MODULE},
 {loop,{?MODULE,loop}},
 {port, 2234}]).
loop(Req) ->
    handle(Req:get(path), Req).

handle("/get_term", Req) ->
    X = [{struct,[{string,<<"joe">>},
  {int,42},
  {float,3.14159}]},
 123,
 <<"a string">>],
    E = mochijson2:encode(X),
    Req:ok({mochiweb_mime:from_extension(".js"),[],E});

The complex term is in the variable X. This is encoded with
mochijson2:encode(X)

Step 3
======

handle(x) is called in the browser - remember step 1? - handle is defined
like this:

function handle(x){
    console.log('got',x);
    $.ajax({url:'echo',
    data:JSON.stringify(x),
    success:function(y){
$("#ret").html(y);
    }});
};

This prints the reply on the console and sends it back to Erlang.
To do this I call JSON.stringify(x). This seems to work correctly.

Step 4
======

Receive the reply in Erlang. I add an addition clause to handle/2,

handle("/echo", Req) ->
    X = json_to_erl(Req),
    io:format("~p~n",[X]),
    ...

where:

json_to_erl(Req) ->
    [{Str,[]}] = Req:parse_qs(),
    mochijson2:decode(Str).

This however is not quite right. The decoded version has changed
all the keys in the hashmap from atoms to binaries.

So when I send {struct, [{a,123}]} I get back {struct,[{<<"a">>,123}]}

This is easy to fix with:

munge({struct,L}) ->
    {struct,[{list_to_atom(binary_to_list(I)), munge(J)} || {I,J}<-L]};
munge(L) when is_list(L) ->
    [munge(I) || I <- L];
munge(X) -> X.

so  the final version is:

json_to_erl(Req) ->
    [{Str,[]}] = Req:parse_qs(),
    munge(mochijson2:decode(Str)).

and amazingly the round trip succeeds. Why am I amazed? - the float
got reconstructed with full precision, and the order of the keys in
the hashmap was preserved.

To summarize:

    1) mochijson2:encode(X) to term an erlang term to JSON

    2) use the jquery function ajax to receive the term
       called like this:

       $.ajax({url:...,
               dataType:'json',
               success:function(x){ ...}
              }).

    3) use the jquery function ajax to send a javascript object x like this:

       $.ajax({url:...
               data:JSON.stringify(x),
               ...})

     4) decode the object in erlang with (assuming Str is the return value
of
        JSON.stringify(x))

          munge(mochijson2:decode(Str))

So far my Erlang strings only contain simple english alphabetic characters,
so I don't really know what will happen if we get into utf8 encoded unicode
strings.
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://erlang.org/pipermail/erlang-questions/attachments/20111125/b7d3a57f/attachment.htm>


More information about the erlang-questions mailing list