Json, in a jiffy!

Working with json in Erlang has vastly improved since the last time I looked at it, particularly with the addition of maps to the language (in R17).

-module(foo_handler).

-export([init/3]).
-export([allowed_methods/2, content_types_accepted/2]).
-export([foo/2]).

init(_Transport, _Req, []) ->
    {upgrade, protocol, cowboy_rest}.

allowed_methods(Req, State) ->
    {[<<"POST">>], Req, State}.

content_types_accepted(Req, State) ->
    {[
        {<<"application/json">>, foo}
    ], Req, State}.

foo(Req, State) ->
    {ok, Body, Req1} = cowboy_req:body(Req),
    Json = jiffy:decode(Body, [return_maps]),
    Bar = maps:get(<<"bar">>, Json),
    {ok, Res} = do_something(Bar),
    Body = jiffy:encode(#{result => Res}),
    {true, cowboy_req:set_resp_body(Body, Req1), State}.

Application metadata file exists but is malformed

I was playing around with Cowboy recently. I had followed the Getting Started guide, but was hoping to avoid having to get into releases. Sadly, the easiest way to serve static files is from an application priv_dir.

I created a relx.config file, but when I ran make I got a cryptic error:

===> Starting relx build process ...
===> Resolving OTP Applications from directories:
          /vagrant/ebin
          /vagrant/deps
          /usr/local/lib/erlang/lib
===> Application metadata file exists but is malformed: /vagrant/ebin/my_app.app
===> Resolving available OTP Releases from directories:
          /vagrant/ebin
          /vagrant/deps
          /usr/local/lib/erlang/lib
Failed to solve release:
 Dependency my_app is specified as a dependency but is not reachable by the system.

I was pretty sure my app metadata file wasn’t malformed, but a quick dig through the sauce led me back to an ominous warning in the cowboy docs:

the modules line will be replaced with the list of modules during compilation; make sure to leave this line even if you do not use it directly

Adding an empty modules list was enough to build a release successfully:

{application, my_app, [
    {description, "My App"},
    ...
    {modules, []},
    ...
]}.
===> Starting relx build process ...
===> Resolving OTP Applications from directories:
          /vagrant/ebin
          /vagrant/deps
          /usr/local/lib/erlang/lib
===> Resolving available OTP Releases from directories:
          /vagrant/ebin
          /vagrant/deps
          /usr/local/lib/erlang/lib
===> Resolved my_app-1
===> Including Erts from /usr/local/lib/erlang
===> release successfully created!