Skip to content

Commit

Permalink
Merge pull request #128 from lafirest/fix/unallowed
Browse files Browse the repository at this point in the history
fix: adjust the structure of `handler` and `handler state`
  • Loading branch information
lafirest authored Oct 10, 2024
2 parents 6c61a64 + 2b4234d commit 30b4e41
Show file tree
Hide file tree
Showing 3 changed files with 46 additions and 23 deletions.
9 changes: 8 additions & 1 deletion include/minirest.hrl
Original file line number Diff line number Diff line change
Expand Up @@ -62,7 +62,6 @@

-record(handler, {
method :: http_method(),
path :: string(),
module :: atom(),
function :: atom(),
filter :: fun(),
Expand All @@ -71,6 +70,14 @@
error_codes :: list(error_code())
}).

-type handler() :: #handler{}.

-type handler_state() :: #{
path := path(),
log := {module(), atom(), InitMeta :: map()} | undefined,
methods := #{http_method() => handler()}
}.

-define(MFA, {?MODULE, ?FUNCTION_NAME, ?FUNCTION_ARITY}).
-define(LOG(Level, Data), logger:log(Level, Data, #{mfa => ?MFA, line => ?LINE})).

Expand Down
38 changes: 21 additions & 17 deletions src/minirest_handler.erl
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@

%%==============================================================================================
%% cowboy callback init
-spec init(_, handler_state()) -> {ok, _, handler_state()}.
init(Request0, State)->
ReqStart = erlang:monotonic_time(),
{Code, Request1} = handle(Request0, State),
Expand All @@ -45,28 +46,29 @@ update_log_meta(New) ->

%%%==============================================================================================
%% internal
handle(Request, #{methods := Methods} = _State) ->
handle(Request, #{path := Path, methods := Methods} = State) ->
Method = cowboy_req:method(Request),
OperationId = list_to_binary(Path),
case maps:find(Method, Methods) of
error ->
StatusCode = ?RESPONSE_CODE_METHOD_NOT_ALLOWED,
Headers = allow_method_header(maps:keys(Methods)),
init_log_meta(Headers#{method => binary_to_existing_atom(Method)}),
init_log_meta(Headers#{operation_id => OperationId, method => minirest_trails:atom_method(Method)}),
{
StatusCode,
cowboy_req:reply(StatusCode, Headers, <<"">>, Request)
};
{ok, Handler = #handler{path = Path, log_meta = LogMeta, method = MethodAtom}} ->
init_log_meta(LogMeta#{operation_id => list_to_binary(Path), method => MethodAtom}),
{ok, Handler = #handler{log_meta = LogMeta, method = MethodAtom}} ->
init_log_meta(LogMeta#{operation_id => OperationId, method => MethodAtom}),
case do_authorize(Request, Handler) of
{ok, AuthMeta} ->
update_log_meta(AuthMeta),
case do_parse_params(Request) of
{ok, Params, NRequest} ->
case do_validate_params(Params, Handler) of
case do_validate_params(Params, State, Handler) of
{ok, NParams} ->
prepend_log_meta(NParams),
Response = apply_callback(NRequest, NParams, Handler),
Response = apply_callback(NRequest, NParams, State, Handler),
{StatusCode, NRequest1} = reply(Response, NRequest, Handler),
{
StatusCode,
Expand Down Expand Up @@ -148,22 +150,24 @@ do_read_body(Request, Params) ->
{ok, Params, Request}
end.

do_validate_params(Params, #handler{filter = Filter,
path = Path,
module = Mod,
method = Method}) when is_function(Filter, 2) ->
do_validate_params(Params, #{path := Path}, #handler{
filter = Filter,
module = Mod,
method = Method
}) when is_function(Filter, 2) ->
Filter(Params, #{path => Path, module => Mod, method => Method});
do_validate_params(Params, Handler = #handler{filter = [Filter | Rest]}) ->
case do_validate_params(Params, Handler#handler{filter = Filter}) of
do_validate_params(Params, State, Handler = #handler{filter = [Filter | Rest]}) ->
case do_validate_params(Params, State, Handler#handler{filter = Filter}) of
{ok, NParams} ->
do_validate_params(NParams, Handler#handler{filter = Rest});
Error -> Error
do_validate_params(NParams, State, Handler#handler{filter = Rest});
Error ->
Error
end;
do_validate_params(Params, _Handler) ->
do_validate_params(Params, _State, _Handler) ->
{ok, Params}.

apply_callback(Request, Params, Handler) ->
#handler{path = Path, method = Method, module = Mod, function = Fun} = Handler,
apply_callback(Request, Params, #{path := Path}, Handler) ->
#handler{method = Method, module = Mod, function = Fun} = Handler,
try
Args =
case erlang:function_exported(Mod, Fun, 3) of
Expand Down
22 changes: 17 additions & 5 deletions src/minirest_trails.erl
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,8 @@

-export([trails_schemas/1]).

-export([atom_method/1]).

-define(HANDLER, minirest_handler).

trails_schemas(Options) ->
Expand Down Expand Up @@ -63,12 +65,11 @@ trails_schemas(BasePath, Authorization, Log, Module, {Path, Metadata, Function})
trails_schemas(BasePath, Authorization, Log, Module, {Path, Metadata, Function, #{}});
trails_schemas(BasePath, Authorization, Log, Module, {Path, Metadata, Function, Options}) ->
Fun =
fun(Method, MethodDef, HandlerStates) ->
fun(Method, MethodDef, MethodStates) ->
#{responses := Responses} = MethodDef,
ErrorCodes = maps:fold(fun get_error_codes/3, [], Responses),
HandlerState = #handler{
method = Method,
path = Path,
module = Module,
function = Function,
authorization = maps:get(security, MethodDef, []) =/= [] andalso Authorization,
Expand All @@ -77,12 +78,12 @@ trails_schemas(BasePath, Authorization, Log, Module, {Path, Metadata, Function,
error_codes = ErrorCodes
},
minirest_info_api:add_codes(ErrorCodes),
maps:put(binary_method(Method), HandlerState, HandlerStates)
maps:put(binary_method(Method), HandlerState, MethodStates)
end,
MethodStates = maps:fold(Fun, #{}, Metadata),
HandlerStates = #{log => Log, methods => MethodStates},
HandlerState = #{path => Path, log => Log, methods => MethodStates},
CompletePath = append_base_path(BasePath, Path),
trails:trail(CompletePath, ?HANDLER, HandlerStates, Metadata).
trails:trail(CompletePath, ?HANDLER, HandlerState, Metadata).

-define(NEST_CODE_KEYS, [<<"content">>,
<<"application/json">>,
Expand Down Expand Up @@ -189,6 +190,17 @@ binary_method(options) -> <<"OPTION">>;
binary_method(connect) -> <<"CONNECT">>;
binary_method(trace) -> <<"TRACE">>.

atom_method(<<"GET">>) -> get;
atom_method(<<"POST">>) -> post;
atom_method(<<"PUT">>) -> put;
atom_method(<<"HEAD">>) -> head;
atom_method(<<"DELETE">>) -> delete;
atom_method(<<"PATCH">>) -> patch;
atom_method(<<"OPTION">>) -> options;
atom_method(<<"CONNECT">>) -> connect;
atom_method(<<"TRACE">>) -> trace.


assert_module_api_specs(ModuleApiSpec) ->
case [E || E = {error, _} <- ModuleApiSpec] of
[] -> ok;
Expand Down

0 comments on commit 30b4e41

Please sign in to comment.