Erlang製のWebフレームワークMochiWebをさらっと触ってみたでござるの巻(その4)

今回はURLから受け取ったパラメータをもとにJSONでレスポンスを返してみます。APIでよくあるパターンですね。
今回はmochijson2の使い方をさらっと見た上で前回のソースにちょっと追加します。

過去記事はこちら
Erlang製のWebフレームワークMochiWebをさらっと触ってみたでござるの巻
Erlang製のWebフレームワークMochiWebをさらっと触ってみたでござるの巻(その2)
Erlang製のWebフレームワークMochiWebをさらっと触ってみたでござるの巻(その3)

mochijson2の使い方
僕自身がちゃんと解ってるか若干あやしいところがあるのですが...ともかくVoluntasさんの記事を見て色々やってみました、あと、mochiwebは各モジュールのソースに自身のテストコードが書いてあるので、それを見ると理解の助けになります。
Voluntasさんの記事「mochijson2 の使い方」
mochijson2のソースコード

例えば

[{"name", <<"shin">>}]

のようなデータをJSONに変換したければ

iolist_to_binary(mochijson2:encode({struct, [{"name", <<"shin">>}]})).
<<"{\"name\":\"shin\"}">>

こんな感じ。
もう少し複雑に

 [{"name", <<"shin">>}, 
  {"age", 36}, 
  {"sex", <<"male">>},
  {"lang", [<<"ruby">>, <<"objective-c">>, <<"erlang">>]}];

だと、

iolist_to_binary(mochijson2:encode({struct, [{"name", <<"shin">>}, 
                                                                    {"age", 36}, 
                                                                    {"sex", <<"male">>},
                                                                    {"lang", [<<"ruby">>, <<"objective-c">>, <<"erlang">>]}]})).

<<"{\"name\":\"shin\",\"age\":36,\"sex\":\"male\",\"lang\":[\"ruby\",\"objective-c\",\"erlang\"]}">>

てな具合で。

JSONでデータを返すサンプルコード
以上のmochijson2の使い方をふまえた上で前回のコードにJSONでレスポンスを返す関数を追加します。
http://localhost:9999/user/show/[ユーザ名]
のようなリクエストに対してそのユーザ情報をJSONで返します。

-module(user_action).

-include_lib("eunit/include/eunit.hrl").

-export([start/1, stop/0]).


start(Port) ->
    mochiweb_http:start([{port, Port}, {loop, fun dispatch/1}]).

stop()->
    mochiweb_http:stop().

%%%===================================================================
%%% Reqest Dispatcher
%%%===================================================================

dispatch(Req) ->
    Path = Req:get(path),
    Params = Req:parse_qs(),

    case string:tokens(Path, "/") of
        [Controller, Action | UrlParams] ->
            handle(Controller, Action, UrlParams, Params, Req);
        [Controller] ->
            handle(Controller, "index", [], Params, Req);
        [] ->
            handle("top", "index", [], [], Req)
    end.

%%%===================================================================
%%% Request Handlers
%%%===================================================================

handle("top", "index", _Path, _Params, Req) ->
    Req:ok({"text/html", "Welcome!"});

handle("user", "welcome", [Name], _Params, Req) ->
    Req:ok({"text/html", subst("Welcom(in url) ~s!", [Name])});

handle("user", "welcome", [], Params, Req) ->
    Name = proplists:get_value("name", Params),
    Req:ok({"text/html", subst("Welcom(from get) ~s!", [Name])});

%%今回追加分。JSONでレスポンスを返す。
handle("user", "show", [Name], _Params, Req) ->
    case get_user(Name) of
        [] -> 
            Req:not_found();
        User ->
            Json = iolist_to_binary(mochijson2:encode({struct, User})),
            Req:ok({"text/html", Json})
    end;

handle(_, _, _, _, Req) ->
    Req:not_found().

%%%===================================================================
%%% Internal Functions
%%%===================================================================

%% shin,tuna以外は空を返す。
get_user(Name) ->
    case Name of
        "shin" ->
            [{"name", <<"shin">>}, 
             {"age", 36}, 
             {"sex", <<"male">>},
             {"lang", [<<"ruby">>, <<"objective-c">>, <<"erlang">>]}];
        "tuna" ->
            [{"name", <<"tuna">>}, 
             {"age", 3}, 
             {"sex", <<"male">>},
             {"lang", [<<"cat-lang">>]}];
        _ ->
            []
    end.

subst(Template, Values) ->
    list_to_binary(lists:flatten(io_lib:fwrite(Template, Values))).

前回のソースコードJSONでレスポンスを返すコードを追加しました。
get_user/1は実運用ではリレーショナルデータベースとかMnesiaからデータを取得するのでしょうが、そこまでやると要点がぼやけるので今回はハードコーディングしてます。
あとはユーザが存在しなければ"404NotFound"を、存在すればそれをJSONにして返します。

結果
ではいつものようにErlangノードを起動してコンパイル、動作確認します。

$ erl -pa ../mochiweb/ebin
1> c(user_action).
{ok,user_action}

2> user_action:start(9999).
{ok,<0.41.0>}

ユーザshinの情報を取得

ユーザtunaの情報を取得

存在しないユーザの情報を取得して404NotFoundが帰る事を確認

所感
ここまででなんとかJSONでレスポンスを返せるようになりました。既にあるモジュールにJSONAPIを被せるだけであれば、ここまでの内容でもなんとかなりそうです。
あとはMnesiaまたはなにかしらのキーバリューストアを使ったセッション管理とか認証とかありますのでゆっくり学習していこうと思います。だんだんと機能を追加していくのは習得してる実感があって楽しいですねw