JSON and JSON-RPC for Erlang

By: on February 17, 2007

About a month ago, I wrote an implementation of RFC 4627, the JSON RFC, for Erlang. I also implemented JSON-RPC over HTTP, in the form of mod_jsonrpc, a plugin for Erlang’s built-in inets httpd. This makes accessing Erlang services from in-browser Javascript very comfortable and easy indeed.

Downloading the code:

* you can browse the code here on github
* a tarball is available here (note: this is dynamically generated from the HEAD revision in the git repository)
* the git repository holding the code can be retrieved with the command
git clone git://github.com/tonyg/erlang-rfc4627.git

Documentation is available, including notes on how to write a service and how to access it from javascript, and the curious may wish to see the code for an example Erlang JSON-RPC service and its corresponding javascript client.

The JSON codec uses a data type mapping suggested by Joe Armstrong, where strings map to binaries and arrays map to lists.

Coincidentally, on the very same day I started writing my JSON codec, Eric Merritt released his new JSON codec, Ktuo. If I’d seen that, I probably wouldn’t have started writing my own. At the time, the only other implementation I knew of was the json.erl included with yaws, which uses an awkward (to me) encoding and was, at the time I was using it, a bit buggy (decoding “[]” returned an incorrect value – it seems to have been fixed somewhere between yaws 1.64 and 1.68). To an extent, Eric’s rationale for a new JSON codec applies to mine, too, and my other excuse is that the data type mapping where strings become Erlang binaries is much more useful to my application. Your mileage may vary!

FacebookTwitterGoogle+

16 Comments

  1. Sam Ruby says:

    I’m interested in proving patches to support utf-8. For more background (and a link to the first patch), see here.

  2. tonyg says:

    Sam, that’s great stuff! Thank you. I’m very interested in integrating your utf-8 work – I’ll get in touch via email.

    (Update: Er, or I would if I could find an email address for you! :-) I’ll leave a comment on your blog, instead.)

  3. Sam Ruby says:

    Email is required to post a comment, but even you can’t see it?

    In any case, rubys at my weblog’s host.

  4. Mikl Kurkov says:

    Hi!
    Thanks for very good work. I’m interested in your jsonrpc implementation. It seems to work pretty good. But I don’t througly understand is it synchronyse or not. I mean if some rpc request takes long time to proceed will over requests wait for it or they can be proceed in parallel.
    As I can see in current implementation you use genserver:call so it is not possible to proceed other request until previous will proceed. Also with function call – all system will wait current call to return.
    Do you plan implementing async requests in this system. Or may be I misiing something.

  5. rich says:

    there’s also ejson

  6. Daniel Kwiecinski says:

    Hi,

    How easy would be to convert mod_json into yaws appmod? Could you make any suggestion – clues to make this task easier?

    Cheers,
    Daniel

  7. tonyg says:

    Hi Daniel,

    It ought not to be too difficult. It may need a bit of refactoring. The key differences will be separating out the inets-httpd specific way of retrieving the URL, query parameters, and POST body from the HTTP request. The main entry point that inets-httpd uses (after a few trivial calls) is do_rpc/1, and the main workers are parse_jsonrpc/2 and invoke_service_method/6. See also the section “Invoking JSON-RPC procedures from Erlang” in the manual.

  8. tonyg says:

    (By the way, a bunch of the necessary refactorings have been done, and the current codebase works with both mochiweb and inets httpd. Adding yaws support might be straightforward!)

  9. n8 says:

    Hi,

    Thanks for sharing the code! It would be helpful to have installation instructions (or a “make install” target) for those unfamiliar with erlang. I need to install this package as a dependency of rabbitmq-http2 and I’m really not sure that I’ve done it correctly.

    Cheers,
    -n8

  10. Joseph Wayne Norton says:

    Tony – I’m not sure where to submit bug reports. If there is a better place, please let me know.

    There appears to be a bug in rfc426.erl. Here is the report from dialyzer:

    rfc4627.erl:153: The call dict:to_list(Dict::tuple()) does not have an opaque term of type dict() in position 1

    It seems the when clause is missing a is_tuple(Dict) guard.

  11. tonyg says:

    Hi Joe,

    Thanks for the report — here’s fine, or you can email me directly. Dialyzer has found a place where we’re violating what little encapsulation Erlang provides. The code it’s complaining about is examining the tuple-based representation of dicts using element/2 as a guard. The dict module doesn’t provide an is_dict/1, so we kind of have to examine the structure itself; and using element/2 as a guard is safe even when the examined object is not a tuple, or is a 0-ary tuple, because guards don’t throw exceptions, they just “fail”, causing evaluation to proceed to the next clause in the function.

    Eshell V5.6.5  (abort with ^G)
    1> rfc4627:encode(dict:new()).
    "{}"
    2> rfc4627:encode({obj, []}).
    "{}"
    3> rfc4627:encode([1, 2]).
    "[1,2]"
    4> 
    

    I’m not sure there’s any easy way of telling dialyzer that what it has found is a non-error — maybe some explicit typespecs would help?

  12. RobW says:

    I believe there is another bug in the code, unless I am simply using it wrong…

    There doesn’t seem to be a way to nest mappings. Because Erlang doesn’t have a true dictionary data type, it seems it’s simulated using a list of tagged tuples. If you create a JSON “object” (i.e. mapping) that is flat, there is no problem. But there seems to be no way to nest mappings.

    For example, this works:
    rfc4627:encode( {obj, [{a,1}, {b,1}]} ).

    But this won’t work:
    rfc4627:encode( {obj, [{a,1}, {b,[{c,3},{d,4}]}]} ).

    Yet I believe nested mappings are legal in JSON. They certainly work fine with Python 2.6 and the json module.

    Both of these would work for Python:
    json.dumps({‘a':1, ‘b':2})
    json.dumps({‘a':1, ‘b': {‘c':3, ‘d':4}})

  13. mikeb says:

    @RobW, you want

    rfc4627:encode( {obj, [{a,1}, {b, {obj, [{c,3},{d,4}]}}]} )

Post a comment

Your email address will not be published.

*

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>