Packages
nova
0.9.19
0.15.1
0.14.3
0.14.1
0.13.7
0.13.1
0.13.0
0.12.1
0.12.0
0.11.0
0.10.4
0.10.3
0.10.2
0.10.1
0.10.0
0.9.24
0.9.23
0.9.22
0.9.21
0.9.20
0.9.19
0.9.18
0.9.17
0.9.16
0.9.15
0.9.11
0.9.5
0.9.4
0.9.3
0.9.2
0.9.1
0.9.0
0.8.6
0.8.5
0.8.4
0.8.3
0.8.2
0.8.1
0.8.0
0.7.2
0.7.1
0.7.0
0.6.2
0.6.1
0.6.0
0.5.2
0.5.1
0.4.4
0.4.3
0.4.2
0.4.1
0.2.2
0.1.0
0.0.1
0.0.0
Nova is a web application framework
Current section
Files
Jump to
Current section
Files
src/plugins/nova_request_plugin.erl
-module(nova_request_plugin).
-behaviour(nova_plugin).
-export([
pre_request/2,
post_request/2,
plugin_info/0
]).
%%--------------------------------------------------------------------
%% @doc
%% Pre-request callback
%% @end
%%--------------------------------------------------------------------
-spec pre_request(Req :: cowboy_req:req(), Options :: map()) ->
{ok, Req0 :: cowboy_req:req()}.
pre_request(Req, Options) ->
ListOptions = maps:to_list(Options),
%% Read the body and put it into the Req object
BodyReq = case cowboy_req:has_body(Req) of
true ->
read_body(Req, <<>>);
false ->
Req#{body => <<>>}
end,
{ok, _} = modulate_state(BodyReq, ListOptions).
%%--------------------------------------------------------------------
%% @doc
%% Post-request callback
%% @end
%%--------------------------------------------------------------------
-spec post_request(Req :: cowboy_req:req(), Options :: map()) ->
{ok, Req0 :: cowboy_req:req()}.
post_request(Req, _Options) ->
{ok, Req}.
%%--------------------------------------------------------------------
%% @doc
%% nova_plugin callback. Returns information about the plugin.
%% @end
%%--------------------------------------------------------------------
-spec plugin_info() -> {Title :: binary(),
Version :: binary(),
Author :: binary(),
Description :: binary(),
Options :: [{Key :: atom(), OptionDescription :: binary()}]}.
plugin_info() ->
{<<"Nova body plugin">>,
<<"0.0.1">>,
<<"Nova team <info@novaframework.org">>,
<<"This plugin modulates the body of a request.">>,
[
{parse_bindings, <<"Used to parse bindings and put them in state under `bindings` key">>},
{decode_json_body, <<"Decodes the body as JSON and puts it under `json`">>},
{parse_qs, <<"Used to parse qs and put hem in state under `qs` key">>}
]}.
%%%%%%%%%%%%%%%%%%%%%%
%% Private functions
%%%%%%%%%%%%%%%%%%%%%%
modulate_state(Req, []) ->
{ok, Req};
modulate_state( Req = #{method := Method}, [{decode_json_body, true}|Tail]) when Method =:= <<"GET">>; Method =:= <<"DELETE">> ->
modulate_state(Req, Tail);
modulate_state(Req = #{headers := #{<<"content-type">> := <<"application/json", _/binary>>}, body := Body}, [{decode_json_body, true}|Tl]) ->
%% Decode the data
JsonLib = nova:get_env(json_lib, thoas),
case erlang:apply(JsonLib, decode, [Body]) of
{ok, JSON} ->
modulate_state(Req#{json => JSON}, Tl);
Error ->
Req400 = cowboy_req:reply(400, Req),
logger:warning(#{status_code => 400,
msg => "Failed to decode json.",
error => Error}),
{stop, Req400}
end;
modulate_state(#{headers := #{<<"content-type">> := <<"application/x-www-form-urlencoded", _/binary>>}, body := Body} = Req,
[{read_urlencoded_body, true}|Tl]) ->
Data = cow_qs:parse_qs(Body),
%% First read in the body
Params = maps:from_list(Data),
modulate_state(Req#{params => Params}, Tl);
modulate_state(Req, [{parse_qs, Type}|T1]) ->
Qs = cowboy_req:parse_qs(Req),
case Type of
true -> MapQs = maps:from_list(Qs),
modulate_state(Req#{parsed_qs => MapQs}, T1);
list -> modulate_state(Req#{parsed_qs => Qs}, T1)
end;
modulate_state(State, [_|Tl]) ->
modulate_state(State, Tl).
read_body(Req, Acc) ->
case cowboy_req:read_body(Req) of
{ok, Data, Req0} -> Req0#{body => Data};
{more, Data, Req0} -> read_body(Req0, <<Data/binary, Acc/binary>>)
end.