src/nine_mid.erl

-module(nine_mid).

-export([urlencoded_params/1, json_request/1, json_response/1]).

-spec urlencoded_params(map()) -> map().
urlencoded_params(Context = #{req := Req, params := Params}) ->
    case elli_request:get_header(<<"Content-Type">>, Req) of
        <<"application/x-www-form-urlencoded">> ->
            PostParams =
                maps:from_list(
                    elli_request:post_args_decoded(Req)),
            Context#{params => maps:merge(Params, PostParams)};
        _ ->
            Context
    end.

-spec json_request(map()) -> map().
json_request(Context = #{req := Req}) ->
    case elli_request:get_header(<<"Content-Type">>, Req) of
        <<"application/json">> ->
            case thoas:decode(
                     elli_request:body(Req))
            of
                {ok, Json} ->
                    Context#{json => Json};
                _ ->
                    Context#{response => {500, [], <<"JSON Decoding Error">>}}
            end;
        _ ->
            Context#{response => {400, [], <<"Expected JSON">>}}
    end.

-spec json_response(map()) -> {integer(), list(), binary()}.
json_response(#{draft := Draft, status := Status}) ->
    {Status, [{<<"Content-Type">>, <<"application/json">>}], thoas:encode(Draft)};
json_response(#{draft := Draft}) ->
    {200, [{<<"Content-Type">>, <<"application/json">>}], thoas:encode(Draft)};
json_response(Context) ->
    Context.

-ifdef(TEST).

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

urlencoded_params_test() ->
    Req = #req{headers = []},
    ?assertEqual(#{req => Req, params => #{}},
                 urlencoded_params(#{req => Req, params => #{}})),

    Req1 =
        #req{headers = [{<<"Content-Type">>, <<"application/x-www-form-urlencoded">>}],
             body = <<"foo=stuff">>},
    ?assertEqual(#{req => Req1, params => #{foo => <<"bar">>, <<"foo">> => <<"stuff">>}},
                 urlencoded_params(#{req => Req1, params => #{foo => <<"bar">>}})).

json_request_test() ->
    Req = #req{headers = []},
    ?assertEqual(#{req => Req, response => {400, [], <<"Expected JSON">>}},
                 json_request(#{req => Req})),

    Req1 =
        #req{headers = [{<<"Content-Type">>, <<"application/json">>}],
             body = <<"{\"foo\":\"bar\"}">>},
    ?assertEqual(#{req => Req1, json => #{<<"foo">> => <<"bar">>}},
                 json_request(#{req => Req1})),

    Req2 =
        #req{headers = [{<<"Content-Type">>, <<"application/json">>}],
             body = <<"{\"foo\":\"bar}">>},
    ?assertEqual(#{req => Req2, response => {500, [], <<"JSON Decoding Error">>}},
                 json_request(#{req => Req2})).

json_response_test() ->
    ?assertEqual(#{}, json_response(#{})),
    ?assertEqual({200,
                  [{<<"Content-Type">>, <<"application/json">>}],
                  <<"{\"foo\":\"bar\"}">>},
                 json_response(#{draft => #{<<"foo">> => <<"bar">>}})),
    ?assertEqual({500,
                  [{<<"Content-Type">>, <<"application/json">>}],
                  <<"{\"foo\":\"bar\"}">>},
                 json_response(#{draft => #{<<"foo">> => <<"bar">>}, status => 500})).

-endif.