From f63d505f84c34aab7b79585b9f732532d73a98ce Mon Sep 17 00:00:00 2001 From: Artem Ocheredko Date: Thu, 25 Aug 2016 15:19:34 +0000 Subject: [PATCH 1/5] CAPI-23 Add understandable messages in case of bad requests --- .../main/resources/erlang-server/api.mustache | 27 ++++++++--- .../resources/erlang-server/handler.mustache | 45 +++++++++++++++++-- 2 files changed, 62 insertions(+), 10 deletions(-) diff --git a/modules/swagger-codegen/src/main/resources/erlang-server/api.mustache b/modules/swagger-codegen/src/main/resources/erlang-server/api.mustache index 9da544fe73d..633829773d1 100644 --- a/modules/swagger-codegen/src/main/resources/erlang-server/api.mustache +++ b/modules/swagger-codegen/src/main/resources/erlang-server/api.mustache @@ -117,8 +117,8 @@ validate( Rule = {type, 'integer'}, Name, Value, _ValidatorState) -> try {ok, {{packageName}}_utils:to_int(Value)} catch - _:Error -> - validation_error(Rule, {Name, Error}) + _:_ -> + validation_error(Rule, Name) end; validate( Rule = {type, 'float'}, Name, Value, _ValidatorState) -> @@ -223,16 +223,31 @@ validate( Rule = schema, Name, Value, ValidatorState) -> validate_with_schema(Value, Definition, ValidatorState), ok catch - _:_ -> - validation_error(Rule, Name) + throw:[{schema_invalid, _, Error} | _] -> + Info = #{ + type => schema_invalid, + error => Error + }, + validation_error(Rule, Name, Info); + throw:[{data_invalid, Schema, Error, _, Path} | _] -> + Info = #{ + type => data_invalid, + error => Error, + schema => Schema, + path => Path + }, + validation_error(Rule, Name, Info) end; validate(Rule, Name, Value, _ValidatorState) -> io:format("Skipping unknown validation: ~p~n", [{Rule, Name, Value}]), ok. -validation_error(Name, Violated) -> - throw({wrong_param, Name, Violated}). +validation_error(ViolatedRule, Name) -> + validation_error(ViolatedRule, Name, #{}). + +validation_error(ViolatedRule, Name, Info) -> + throw({wrong_param, Name, ViolatedRule, Info}). get_value(body, _Name, Req0) -> {ok, Body, Req} = cowboy_req:body(Req0), diff --git a/modules/swagger-codegen/src/main/resources/erlang-server/handler.mustache b/modules/swagger-codegen/src/main/resources/erlang-server/handler.mustache index db72b2739b4..375bd65bd7e 100644 --- a/modules/swagger-codegen/src/main/resources/erlang-server/handler.mustache +++ b/modules/swagger-codegen/src/main/resources/erlang-server/handler.mustache @@ -31,6 +31,10 @@ init(_Transport, Req, Opts) -> rest_init(Req0, [Operations, LogicHandler, ValidatorState]) -> {Method, Req} = cowboy_req:method(Req0), OperationID = maps:get(Method, Operations, undefined), + + Message = io_lib:format("Attempt to process operation: ~p", [OperationID]), + report(info, Message), + State = #state{ operation_id = OperationID, logic_handler = LogicHandler, @@ -96,6 +100,28 @@ valid_entity_length(Req, State) -> {true, Req, State}. %%%% + +-type handle_response() :: + {ok, {Status :: cowboy:http_status(), Headers :: cowboy:http_headers(), Body :: iodata()}, Req :: cowboy_req:req()} | + {error, Reason :: any(), Req :: cowboy_req:req()}. + +-spec handle_request(Response :: handle_response(), #state{}, cowboy_req:req()) -> {halt, cowboy_req:req(), #state{}}. + +handle_request(Response, Req0, State = #state{operation_id = OperationID}) -> + case Response of + {ok, {Code, Headers, Body}} -> + {ok, Req} = cowboy_req:reply(Code, Headers, Body, Req0), + {halt, Req, State}; + {error, Message} -> + Reason = io_lib:format("Unable to process request for ~p: ~p", [OperationID, Message]), + report(error, Reason), + + {ok, Req} = cowboy_req:reply(400, Req0), + {halt, Req, State} + end. + +-spec handle_request_json(cowboy_req:req(), #state{}) -> {halt, cowboy_req:req(), #state{}}. + handle_request_json( Req0, State = #state{ @@ -111,11 +137,22 @@ handle_request_json( {Code, Headers, Body} -> {{packageName}}_api:validate_response(OperationID, Code, Body , ValidatorState), PreparedBody = jsx:encode(Body), - {ok, Req} = cowboy_req:reply(Code, Headers, PreparedBody, Req1), - {halt, Req, State} + Response = {ok, {Code, Headers, PreparedBody}}, + handle_request(Response, Req1, State) end; - {error, _Reason, Req1} -> - {false, Req1, State} + {error, Reason, Req1} -> + handle_request({error, Reason}, Req1, State) end. validate_headers(_, Req) -> {true, Req}. + +-spec report(Level :: error | info | warning, Message :: iodata()) -> ok. + +report(info, Message) -> + error_logger:info_msg(Message); + +report(warning, Message) -> + error_logger:warning_msg(Message); + +report(error, Message) -> + error_logger:error_msg(Message). From 97dfb921b03330e1ebdb7ed78d13948f3960fa70 Mon Sep 17 00:00:00 2001 From: Artem Ocheredko Date: Mon, 29 Aug 2016 12:08:48 +0300 Subject: [PATCH 2/5] CAPI-23 Add specs to shut up dialyzer and add some minor code refactoring --- .../main/resources/erlang-server/api.mustache | 29 ++++++--- .../resources/erlang-server/auth.mustache | 9 +++ .../default_logic_handler.mustache | 10 ++- .../resources/erlang-server/handler.mustache | 63 ++++++++++++++----- .../resources/erlang-server/router.mustache | 2 + .../resources/erlang-server/server.mustache | 18 ++++-- .../resources/erlang-server/utils.mustache | 11 ++++ 7 files changed, 110 insertions(+), 32 deletions(-) diff --git a/modules/swagger-codegen/src/main/resources/erlang-server/api.mustache b/modules/swagger-codegen/src/main/resources/erlang-server/api.mustache index 633829773d1..17df212d4fc 100644 --- a/modules/swagger-codegen/src/main/resources/erlang-server/api.mustache +++ b/modules/swagger-codegen/src/main/resources/erlang-server/api.mustache @@ -5,7 +5,7 @@ -export([populate_request/3]). -export([validate_response/4]). - +-spec request_params(OperationID :: atom()) -> [Param :: atom()]. {{#apiInfo}}{{#apis}} {{#operations}}{{#operation}} request_params('{{operationId}}') -> @@ -17,6 +17,11 @@ request_params('{{operationId}}') -> request_params(_) -> error(unknown_operation). +-spec request_param_info(OperationID :: atom(), Name :: atom()) -> #{ + source => qs_val | binding | header | body, + rules => [any()] +}. + {{#apiInfo}}{{#apis}} {{#operations}}{{#operation}}{{#allParams}} request_param_info('{{operationId}}', {{^isBodyParam}}'{{baseName}}'{{/isBodyParam}}{{#isBodyParam}}'{{dataType}}'{{/isBodyParam}}) -> @@ -50,6 +55,9 @@ request_param_info('{{operationId}}', {{^isBodyParam}}'{{baseName}}'{{/isBodyPar request_param_info(OperationID, Name) -> error({unknown_param, OperationID, Name}). +-spec populate_request(OperationID :: atom(), Req :: cowboy_req:req(), ValidatorState :: jesse_state:state()) +-> {ok, Model :: #{}, Req :: cowboy_req:req()} | {error, Reason :: any(), Req :: cowboy_req:req()}. + populate_request(OperationID, Req, ValidatorState) -> Params = request_params(OperationID), populate_request_params(OperationID, Params, Req, ValidatorState, #{}). @@ -74,7 +82,12 @@ populate_request_param(OperationID, Name, Req0, ValidatorState) -> {error, Reason, Req} end. - +-spec validate_response( + OperationID :: atom(), + Code :: integer(), + Body :: binary(), + ValidatorState :: jesse_state:state() +) -> ok | no_return(). {{#apiInfo}}{{#apis}} {{#operations}}{{#operation}} {{#responses}} @@ -86,12 +99,6 @@ validate_response('{{operationId}}', {{code}}, Body, ValidatorState) -> validate_response(_OperationID, _Code, _Body, _ValidatorState) -> ok. -validate_response_body(undefined, _, Body, _) -> - case Body of - #{} -> ok; - _ -> throw(invalid_response) - end; - validate_response_body('list', ReturnBaseType, Body, ValidatorState) -> [ validate(schema, ReturnBaseType, Item, ValidatorState) @@ -220,7 +227,7 @@ validate( Rule = {pattern, Pattern}, Name, Value, _ValidatorState) -> validate( Rule = schema, Name, Value, ValidatorState) -> Definition = list_to_binary("#/definitions/" ++ {{packageName}}_utils:to_list(Name)), try - validate_with_schema(Value, Definition, ValidatorState), + _ = validate_with_schema(Value, Definition, ValidatorState), ok catch throw:[{schema_invalid, _, Error} | _] -> @@ -243,9 +250,13 @@ validate(Rule, Name, Value, _ValidatorState) -> io:format("Skipping unknown validation: ~p~n", [{Rule, Name, Value}]), ok. +-spec validation_error(Rule :: any(), Name :: any()) -> no_return(). + validation_error(ViolatedRule, Name) -> validation_error(ViolatedRule, Name, #{}). +-spec validation_error(Rule :: any(), Name :: any(), Info :: #{}) -> no_return(). + validation_error(ViolatedRule, Name, Info) -> throw({wrong_param, Name, ViolatedRule, Info}). diff --git a/modules/swagger-codegen/src/main/resources/erlang-server/auth.mustache b/modules/swagger-codegen/src/main/resources/erlang-server/auth.mustache index 624e86cf064..5b13b6d6037 100644 --- a/modules/swagger-codegen/src/main/resources/erlang-server/auth.mustache +++ b/modules/swagger-codegen/src/main/resources/erlang-server/auth.mustache @@ -2,6 +2,15 @@ -export([authorize_api_key/5]). +-spec authorize_api_key( + From :: header | qs_val, + KeyParam :: iodata() | atom(), + OperationID :: atom(), + Req ::cowboy_req:req(), + LogicHandler :: atom()) +-> {true, Context :: #{binary() => any()}, Req ::cowboy_req:req()} | + {false, AuthHeader :: binary(), Req ::cowboy_req:req()}. + authorize_api_key(From, KeyParam, OperationID, Req0, LogicHandler) -> {ApiKey, Req} = get_api_key(From, KeyParam, Req0), case ApiKey of diff --git a/modules/swagger-codegen/src/main/resources/erlang-server/default_logic_handler.mustache b/modules/swagger-codegen/src/main/resources/erlang-server/default_logic_handler.mustache index f42bdc04092..2444ee31e03 100644 --- a/modules/swagger-codegen/src/main/resources/erlang-server/default_logic_handler.mustache +++ b/modules/swagger-codegen/src/main/resources/erlang-server/default_logic_handler.mustache @@ -11,10 +11,16 @@ {{#authMethods}} {{#isApiKey}} +-spec authorize_api_key(ApiKey :: binary(), OperationID :: atom()) -> {true, #{}}. + authorize_api_key(_, _) -> {true, #{}}. {{/isApiKey}} {{/authMethods}} +-spec handle_request(OperationID :: atom(), Req :: cowboy_req:req(), Context :: #{}) +-> {Code :: integer(), Headers :: [], Body :: binary()}. + handle_request(OperationID, Req, Context) -> - io:format(user, "Got request to process: ~p~n", [{OperationID, Req, Context}]), - {501, [], <<"Not Implemented">>}. + Message = io_lib:format("Got not implemented request to process: ~p~n", [{OperationID, Req, Context}]), + error_logger:info_msg(Message), + {501, [], <<"">>}. diff --git a/modules/swagger-codegen/src/main/resources/erlang-server/handler.mustache b/modules/swagger-codegen/src/main/resources/erlang-server/handler.mustache index 375bd65bd7e..8a93cab7d11 100644 --- a/modules/swagger-codegen/src/main/resources/erlang-server/handler.mustache +++ b/modules/swagger-codegen/src/main/resources/erlang-server/handler.mustache @@ -19,15 +19,23 @@ -export([handle_request_json/2]). -record(state, { - operation_id, - logic_handler, - validator_state, - context=#{} + operation_id :: atom(), + logic_handler :: atom(), + validator_state :: jesse_state:state(), + context=#{} :: #{} }). +-type init_opts() :: [any()]. + +-spec init(TransportName :: atom(), Req :: cowboy_req:req(), Opts :: init_opts()) +-> {upgrade, protocol, cowboy_rest, Req :: cowboy_req:req(), Opts :: init_opts()}. + init(_Transport, Req, Opts) -> {upgrade, protocol, cowboy_rest, Req, Opts}. +-spec rest_init(Req :: cowboy_req:req(), Opts :: init_opts()) +-> {ok, Req :: cowboy_req:req(), State :: #state{}}. + rest_init(Req0, [Operations, LogicHandler, ValidatorState]) -> {Method, Req} = cowboy_req:method(Req0), OperationID = maps:get(Method, Operations, undefined), @@ -42,6 +50,9 @@ rest_init(Req0, [Operations, LogicHandler, ValidatorState]) -> }, {ok, Req, State}. +-spec allowed_methods(Req :: cowboy_req:req(), State :: #state{}) +-> {Value :: any(), Req :: cowboy_req:req(), State :: #state{}}. + {{#operations}}{{#operation}} allowed_methods(Req, State = #state{operation_id = '{{operationId}}'}) -> {[<<"{{httpMethod}}">>], Req, State}; @@ -49,6 +60,8 @@ allowed_methods(Req, State = #state{operation_id = '{{operationId}}'}) -> allowed_methods(Req, State) -> {[], Req, State}. +-spec is_authorized(Req :: cowboy_req:req(), State :: #state{}) +-> {Value :: any(), Req :: cowboy_req:req(), State :: #state{}}. {{#operations}}{{#operation}} is_authorized(Req0, State = #state{operation_id = '{{operationId}}' = OperationID, logic_handler = LogicHandler}) -> {{#authMethods}} @@ -64,11 +77,15 @@ is_authorized(Req0, State = #state{operation_id = '{{operationId}}' = OperationI is_authorized(Req, State) -> {{false, <<"">>}, Req, State}. +-spec content_types_accepted(Req :: cowboy_req:req(), State :: #state{}) +-> {Value :: any(), Req :: cowboy_req:req(), State :: #state{}}. content_types_accepted(Req, State) -> {[ {<<"application/json">>, handle_request_json} ], Req, State}. +-spec valid_content_headers(Req :: cowboy_req:req(), State :: #state{}) +-> {Value :: any(), Req :: cowboy_req:req(), State :: #state{}}. {{#operations}}{{#operation}} valid_content_headers(Req0, State = #state{operation_id = '{{operationId}}'}) -> Headers = [{{#headerParams}}"{{baseName}}"{{#hasMore}},{{/hasMore}}{{/headerParams}}], @@ -78,36 +95,55 @@ valid_content_headers(Req0, State = #state{operation_id = '{{operationId}}'}) -> valid_content_headers(Req, State) -> {false, Req, State}. +-spec content_types_provided(Req :: cowboy_req:req(), State :: #state{}) +-> {Value :: any(), Req :: cowboy_req:req(), State :: #state{}}. + content_types_provided(Req, State) -> {[ {<<"application/json">>, handle_request_json} ], Req, State}. +-spec malformed_request(Req :: cowboy_req:req(), State :: #state{}) +-> {Value :: any(), Req :: cowboy_req:req(), State :: #state{}}. + malformed_request(Req, State) -> {false, Req, State}. +-spec allow_missing_post(Req :: cowboy_req:req(), State :: #state{}) +-> {Value :: any(), Req :: cowboy_req:req(), State :: #state{}}. + allow_missing_post(Req, State) -> {false, Req, State}. +-spec delete_resource(Req :: cowboy_req:req(), State :: #state{}) +-> {Value :: any(), Req :: cowboy_req:req(), State :: #state{}}. + delete_resource(Req, State) -> handle_request_json(Req, State). +-spec known_content_type(Req :: cowboy_req:req(), State :: #state{}) +-> {Value :: any(), Req :: cowboy_req:req(), State :: #state{}}. + known_content_type(Req, State) -> {true, Req, State}. +-spec valid_entity_length(Req :: cowboy_req:req(), State :: #state{}) +-> {Value :: any(), Req :: cowboy_req:req(), State :: #state{}}. + valid_entity_length(Req, State) -> %% @TODO check the length {true, Req, State}. %%%% --type handle_response() :: - {ok, {Status :: cowboy:http_status(), Headers :: cowboy:http_headers(), Body :: iodata()}, Req :: cowboy_req:req()} | - {error, Reason :: any(), Req :: cowboy_req:req()}. +-type handler_response() :: + {ok, {Status :: cowboy:http_status(), Headers :: cowboy:http_headers(), Body :: binary()}} | + {error, Reason :: any()}. + +-spec process_response(Response :: handler_response(), cowboy_req:req(), #state{}) -> {halt, cowboy_req:req(), #state{}}. --spec handle_request(Response :: handle_response(), #state{}, cowboy_req:req()) -> {halt, cowboy_req:req(), #state{}}. -handle_request(Response, Req0, State = #state{operation_id = OperationID}) -> +process_response(Response, Req0, State = #state{operation_id = OperationID}) -> case Response of {ok, {Code, Headers, Body}} -> {ok, Req} = cowboy_req:reply(Code, Headers, Body, Req0), @@ -138,21 +174,18 @@ handle_request_json( {{packageName}}_api:validate_response(OperationID, Code, Body , ValidatorState), PreparedBody = jsx:encode(Body), Response = {ok, {Code, Headers, PreparedBody}}, - handle_request(Response, Req1, State) + process_response(Response, Req1, State) end; {error, Reason, Req1} -> - handle_request({error, Reason}, Req1, State) + process_response({error, Reason}, Req1, State) end. validate_headers(_, Req) -> {true, Req}. --spec report(Level :: error | info | warning, Message :: iodata()) -> ok. +-spec report(Level :: error | info, Message :: iodata()) -> ok. report(info, Message) -> error_logger:info_msg(Message); -report(warning, Message) -> - error_logger:warning_msg(Message); - report(error, Message) -> error_logger:error_msg(Message). diff --git a/modules/swagger-codegen/src/main/resources/erlang-server/router.mustache b/modules/swagger-codegen/src/main/resources/erlang-server/router.mustache index 55755ad0a9a..cb71fcc629a 100644 --- a/modules/swagger-codegen/src/main/resources/erlang-server/router.mustache +++ b/modules/swagger-codegen/src/main/resources/erlang-server/router.mustache @@ -2,6 +2,8 @@ -export([get_paths/1]). +-spec get_paths(LogicHandler :: atom()) -> [{'_',[any()]},...]. + get_paths(LogicHandler) -> ValidatorState = prepare_validator(), PreparedPaths = maps:fold( diff --git a/modules/swagger-codegen/src/main/resources/erlang-server/server.mustache b/modules/swagger-codegen/src/main/resources/erlang-server/server.mustache index 67c9a4b862d..90a6388ea5d 100644 --- a/modules/swagger-codegen/src/main/resources/erlang-server/server.mustache +++ b/modules/swagger-codegen/src/main/resources/erlang-server/server.mustache @@ -6,22 +6,28 @@ -export([child_spec/2]). -child_spec(Id, #{ - ip := Ip, +-spec child_spec( ID :: any(), #{ + ip => inet:ip_address(), + port => inet:port_number(), + net_opts => [] +}) -> supervisor:child_spec(). + +child_spec(ID, #{ + ip := IP , port := Port, net_opts := NetOpts } = Params) -> AcceptorsPool = ?DEFAULT_ACCEPTORS_POOLSIZE, - {Transport, TransportOpts} = get_socket_transport(Ip, Port, NetOpts), + {Transport, TransportOpts} = get_socket_transport(IP, Port, NetOpts), LogicHandler = maps:get(logic_handler, Params, ?DEFAULT_LOGIC_HANDLER), ExtraOpts = maps:get(cowboy_extra_opts, Params, []), CowboyOpts = get_cowboy_config(LogicHandler, ExtraOpts), - ranch:child_spec({?MODULE, Id}, AcceptorsPool, + ranch:child_spec({?MODULE, ID}, AcceptorsPool, Transport, TransportOpts, cowboy_protocol, CowboyOpts). -get_socket_transport(Ip, Port, Options) -> +get_socket_transport(IP, Port, Options) -> Opts = [ - {ip, Ip}, + {ip, IP}, {port, Port} ], case {{packageName}}_utils:get_opt(ssl, Options) of diff --git a/modules/swagger-codegen/src/main/resources/erlang-server/utils.mustache b/modules/swagger-codegen/src/main/resources/erlang-server/utils.mustache index 6905501022a..b6701add7fc 100644 --- a/modules/swagger-codegen/src/main/resources/erlang-server/utils.mustache +++ b/modules/swagger-codegen/src/main/resources/erlang-server/utils.mustache @@ -54,6 +54,7 @@ to_int(Data) when is_binary(Data) -> to_int(Data) when is_list(Data) -> list_to_integer(Data). +-spec set_resp_headers([{binary(), iodata()}], cowboy_req:req()) -> cowboy_req:req(). set_resp_headers([], Req) -> Req; @@ -61,20 +62,30 @@ set_resp_headers([{K, V} | T], Req0) -> Req = cowboy_req:set_resp_header(K, V, Req0), set_resp_headers(T, Req). +-spec to_header(iodata() | atom() | number()) -> binary(). + to_header(Name) -> Prepared = to_binary(Name), to_lower(Prepared). +-spec to_qs(iodata() | atom() | number()) -> binary(). + to_qs(Name) -> to_binary(Name). +-spec to_binding(iodata() | atom() | number()) -> atom(). + to_binding(Name) -> Prepared = to_binary(Name), binary_to_atom(Prepared, utf8). +-spec get_opt(any(), []) -> any(). + get_opt(Key, Opts) -> get_opt(Key, Opts, undefined). +-spec get_opt(any(), [], any()) -> any(). + get_opt(Key, Opts, Default) -> case lists:keyfind(Key, 1, Opts) of {_, Value} -> Value; From a48143c2ec58bd9d4d371420c3cf3e98455dbb4c Mon Sep 17 00:00:00 2001 From: Artem Ocheredko Date: Mon, 29 Aug 2016 17:35:06 +0300 Subject: [PATCH 3/5] CAPI-23 Fix logging to use error_logger:msg functionality only. Refactor specs and missed spec. Add minor refactoring. --- .../main/resources/erlang-server/api.mustache | 123 +++++++++------ .../resources/erlang-server/auth.mustache | 33 ++-- .../default_logic_handler.mustache | 18 ++- .../resources/erlang-server/handler.mustache | 149 +++++++++++------- .../erlang-server/logic_handler.mustache | 42 ++++- .../resources/erlang-server/router.mustache | 20 ++- 6 files changed, 262 insertions(+), 123 deletions(-) diff --git a/modules/swagger-codegen/src/main/resources/erlang-server/api.mustache b/modules/swagger-codegen/src/main/resources/erlang-server/api.mustache index 17df212d4fc..91c8a374e7c 100644 --- a/modules/swagger-codegen/src/main/resources/erlang-server/api.mustache +++ b/modules/swagger-codegen/src/main/resources/erlang-server/api.mustache @@ -5,7 +5,11 @@ -export([populate_request/3]). -export([validate_response/4]). --spec request_params(OperationID :: atom()) -> [Param :: atom()]. +-type operation_id() :: atom(). + +-export_type([operation_id/0]). + +-spec request_params(OperationID :: operation_id()) -> [Param :: atom()]. {{#apiInfo}}{{#apis}} {{#operations}}{{#operation}} request_params('{{operationId}}') -> @@ -17,9 +21,29 @@ request_params('{{operationId}}') -> request_params(_) -> error(unknown_operation). --spec request_param_info(OperationID :: atom(), Name :: atom()) -> #{ +-type rule() :: + {type, 'binary'} | + {type, 'integer'} | + {type, 'float'} | + {type, 'binary'} | + {type, 'boolean'} | + {type, 'date'} | + {type, 'datetime'} | + {enum, [atom()]} | + {max, Max :: number()} | + {exclusive_max, Max :: number()} | + {min, Min :: number()} | + {exclusive_min, Min :: number()} | + {max_length, MaxLength :: integer()} | + {min_length, MaxLength :: integer()} | + {pattern, Pattern :: string()} | + schema | + required | + not_required. + +-spec request_param_info(OperationID :: operation_id(), Name :: atom()) -> #{ source => qs_val | binding | header | body, - rules => [any()] + rules => [rule()] }. {{#apiInfo}}{{#apis}} @@ -28,25 +52,25 @@ request_param_info('{{operationId}}', {{^isBodyParam}}'{{baseName}}'{{/isBodyPar #{ source => {{#isQueryParam}}qs_val{{/isQueryParam}} {{#isPathParam}}binding{{/isPathParam}} {{#isHeaderParam}}header{{/isHeaderParam}}{{#isBodyParam}}body{{/isBodyParam}}, rules => [{{#isString}} - {type, 'binary'}, {{/isString}}{{#isInteger}} - {type, 'integer'}, {{/isInteger}}{{#isLong}} - {type, 'integer'}, {{/isLong}}{{#isFloat}} - {type, 'float'}, {{/isFloat}}{{#isDouble}} - {type, 'float'}, {{/isDouble}}{{#isByteArray}} - {type, 'binary'}, {{/isByteArray}}{{#isBinary}} - {type, 'binary'}, {{/isBinary}}{{#isBoolean}} - {type, 'boolean'}, {{/isBoolean}}{{#isDate}} - {type, 'date'}, {{/isDate}}{{#isDateTime}} - {type, 'datetime'}, {{/isDateTime}}{{#isEnum}} + {type, 'binary'},{{/isString}}{{#isInteger}} + {type, 'integer'},{{/isInteger}}{{#isLong}} + {type, 'integer'},{{/isLong}}{{#isFloat}} + {type, 'float'},{{/isFloat}}{{#isDouble}} + {type, 'float'},{{/isDouble}}{{#isByteArray}} + {type, 'binary'},{{/isByteArray}}{{#isBinary}} + {type, 'binary'},{{/isBinary}}{{#isBoolean}} + {type, 'boolean'},{{/isBoolean}}{{#isDate}} + {type, 'date'},{{/isDate}}{{#isDateTime}} + {type, 'datetime'},{{/isDateTime}}{{#isEnum}} {enum, [{{#allowableValues}}{{#values}}'{{.}}'{{^-last}}, {{/-last}}{{/values}}{{/allowableValues}}] },{{/isEnum}}{{#maximum}} {max, {{maximum}} }, {{/maximum}}{{#exclusiveMaximum}} - {exclusive_max, {{exclusiveMaximum}} }, {{/exclusiveMaximum}}{{#minimum}} - {min, {{minimum}} }, {{/minimum}}{{#exclusiveMinimum}} - {exclusive_min, {{exclusiveMinimum}} }, {{/exclusiveMinimum}}{{#maxLength}} - {max_length, {{maxLength}} }, {{/maxLength}}{{#minLength}} - {min_length, {{minLength}} }, {{/minLength}}{{#pattern}} - {pattern, "{{pattern}}" }, {{/pattern}}{{#isBodyParam}} - schema, {{/isBodyParam}}{{#required}} + {exclusive_max, {{exclusiveMaximum}} },{{/exclusiveMaximum}}{{#minimum}} + {min, {{minimum}} },{{/minimum}}{{#exclusiveMinimum}} + {exclusive_min, {{exclusiveMinimum}} },{{/exclusiveMinimum}}{{#maxLength}} + {max_length, {{maxLength}} },{{/maxLength}}{{#minLength}} + {min_length, {{minLength}} },{{/minLength}}{{#pattern}} + {pattern, "{{pattern}}" },{{/pattern}}{{#isBodyParam}} + schema,{{/isBodyParam}}{{#required}} required{{/required}}{{^required}} not_required{{/required}} ] @@ -55,8 +79,13 @@ request_param_info('{{operationId}}', {{^isBodyParam}}'{{baseName}}'{{/isBodyPar request_param_info(OperationID, Name) -> error({unknown_param, OperationID, Name}). --spec populate_request(OperationID :: atom(), Req :: cowboy_req:req(), ValidatorState :: jesse_state:state()) --> {ok, Model :: #{}, Req :: cowboy_req:req()} | {error, Reason :: any(), Req :: cowboy_req:req()}. +-spec populate_request( + OperationID :: operation_id(), + Req :: cowboy_req:req(), + ValidatorState :: jesse_state:state() +) -> + {ok, Model :: #{}, Req :: cowboy_req:req()} | + {error, Reason :: any(), Req :: cowboy_req:req()}. populate_request(OperationID, Req, ValidatorState) -> Params = request_params(OperationID), @@ -83,9 +112,9 @@ populate_request_param(OperationID, Name, Req0, ValidatorState) -> end. -spec validate_response( - OperationID :: atom(), + OperationID :: operation_id(), Code :: integer(), - Body :: binary(), + Body :: jesse:json_term(), ValidatorState :: jesse_state:state() ) -> ok | no_return(). {{#apiInfo}}{{#apis}} @@ -108,7 +137,7 @@ validate_response_body(_, ReturnBaseType, Body, ValidatorState) -> validate(schema, ReturnBaseType, Body, ValidatorState). %%% -validate( Rule = required, Name, Value, _ValidatorState) -> +validate(Rule = required, Name, Value, _ValidatorState) -> case Value of undefined -> validation_error(Rule, Name); _ -> ok @@ -117,35 +146,35 @@ validate( Rule = required, Name, Value, _ValidatorState) -> validate(not_required, _Name, _Value, _ValidatorState) -> ok; -validate( _, _Name, undefined, _ValidatorState) -> +validate(_, _Name, undefined, _ValidatorState) -> ok; -validate( Rule = {type, 'integer'}, Name, Value, _ValidatorState) -> +validate(Rule = {type, 'integer'}, Name, Value, _ValidatorState) -> try {ok, {{packageName}}_utils:to_int(Value)} catch - _:_ -> + error:badarg -> validation_error(Rule, Name) end; -validate( Rule = {type, 'float'}, Name, Value, _ValidatorState) -> +validate(Rule = {type, 'float'}, Name, Value, _ValidatorState) -> try {ok, {{packageName}}_utils:to_float(Value)} catch - _:_ -> + error:badarg -> validation_error(Rule, Name) end; -validate( Rule = {type, 'binary'}, Name, Value, _ValidatorState) -> +validate(Rule = {type, 'binary'}, Name, Value, _ValidatorState) -> case is_binary(Value) of true -> ok; false -> validation_error(Rule, Name) end; -validate( _Rule = {type, 'boolean'}, _Name, Value, _ValidatorState) when is_boolean(Value) -> +validate(_Rule = {type, 'boolean'}, _Name, Value, _ValidatorState) when is_boolean(Value) -> {ok, Value}; -validate( Rule = {type, 'boolean'}, Name, Value, _ValidatorState) -> +validate(Rule = {type, 'boolean'}, Name, Value, _ValidatorState) -> V = binary_to_lower(Value), try case binary_to_existing_atom(V, utf8) of @@ -157,19 +186,19 @@ validate( Rule = {type, 'boolean'}, Name, Value, _ValidatorState) -> validation_error(Rule, Name) end; -validate( Rule = {type, 'date'}, Name, Value, _ValidatorState) -> +validate(Rule = {type, 'date'}, Name, Value, _ValidatorState) -> case is_binary(Value) of true -> ok; false -> validation_error(Rule, Name) end; -validate( Rule = {type, 'datetime'}, Name, Value, _ValidatorState) -> +validate(Rule = {type, 'datetime'}, Name, Value, _ValidatorState) -> case is_binary(Value) of true -> ok; false -> validation_error(Rule, Name) end; -validate( Rule = {enum, Values}, Name, Value, _ValidatorState) -> +validate(Rule = {enum, Values}, Name, Value, _ValidatorState) -> try FormattedValue = erlang:binary_to_existing_atom(Value, utf8), case lists:member(FormattedValue, Values) of @@ -181,50 +210,50 @@ validate( Rule = {enum, Values}, Name, Value, _ValidatorState) -> validation_error(Rule, Name) end; -validate( Rule = {max, Max}, Name, Value, _ValidatorState) -> +validate(Rule = {max, Max}, Name, Value, _ValidatorState) -> case Value >= Max of true -> ok; false -> validation_error(Rule, Name) end; -validate( Rule = {exclusive_max, ExclusiveMax}, Name, Value, _ValidatorState) -> +validate(Rule = {exclusive_max, ExclusiveMax}, Name, Value, _ValidatorState) -> case Value > ExclusiveMax of true -> ok; false -> validation_error(Rule, Name) end; -validate( Rule = {min, Min}, Name, Value, _ValidatorState) -> +validate(Rule = {min, Min}, Name, Value, _ValidatorState) -> case Value =< Min of true -> ok; false -> validation_error(Rule, Name) end; -validate( Rule = {exclusive_min, ExclusiveMin}, Name, Value, _ValidatorState) -> +validate(Rule = {exclusive_min, ExclusiveMin}, Name, Value, _ValidatorState) -> case Value =< ExclusiveMin of true -> ok; false -> validation_error(Rule, Name) end; -validate( Rule = {max_length, MaxLength}, Name, Value, _ValidatorState) -> +validate(Rule = {max_length, MaxLength}, Name, Value, _ValidatorState) -> case size(Value) =< MaxLength of true -> ok; false -> validation_error(Rule, Name) end; -validate( Rule = {min_length, MinLength}, Name, Value, _ValidatorState) -> +validate(Rule = {min_length, MinLength}, Name, Value, _ValidatorState) -> case size(Value) >= MinLength of true -> ok; false -> validation_error(Rule, Name) end; -validate( Rule = {pattern, Pattern}, Name, Value, _ValidatorState) -> +validate(Rule = {pattern, Pattern}, Name, Value, _ValidatorState) -> {ok, MP} = re:compile(Pattern), case re:run(Value, MP) of {match, _} -> ok; _ -> validation_error(Rule, Name) end; -validate( Rule = schema, Name, Value, ValidatorState) -> +validate(Rule = schema, Name, Value, ValidatorState) -> Definition = list_to_binary("#/definitions/" ++ {{packageName}}_utils:to_list(Name)), try _ = validate_with_schema(Value, Definition, ValidatorState), @@ -246,9 +275,9 @@ validate( Rule = schema, Name, Value, ValidatorState) -> validation_error(Rule, Name, Info) end; -validate(Rule, Name, Value, _ValidatorState) -> - io:format("Skipping unknown validation: ~p~n", [{Rule, Name, Value}]), - ok. +validate(Rule, Name, _Value, _ValidatorState) -> + error_logger:info_msg("Can't validate ~p with ~p", [Name, Rule]), + error({unknown_validation_rule, Rule}). -spec validation_error(Rule :: any(), Name :: any()) -> no_return(). diff --git a/modules/swagger-codegen/src/main/resources/erlang-server/auth.mustache b/modules/swagger-codegen/src/main/resources/erlang-server/auth.mustache index 5b13b6d6037..b0555359e3c 100644 --- a/modules/swagger-codegen/src/main/resources/erlang-server/auth.mustache +++ b/modules/swagger-codegen/src/main/resources/erlang-server/auth.mustache @@ -3,22 +3,27 @@ -export([authorize_api_key/5]). -spec authorize_api_key( + LogicHandler :: atom(), + OperationID :: {{packageName}}_api:operation_id(), From :: header | qs_val, KeyParam :: iodata() | atom(), - OperationID :: atom(), - Req ::cowboy_req:req(), - LogicHandler :: atom()) --> {true, Context :: #{binary() => any()}, Req ::cowboy_req:req()} | - {false, AuthHeader :: binary(), Req ::cowboy_req:req()}. + Req ::cowboy_req:req() +)-> {true, Context :: #{binary() => any()}, Req ::cowboy_req:req()} | + {false, AuthHeader :: binary(), Req ::cowboy_req:req()}. -authorize_api_key(From, KeyParam, OperationID, Req0, LogicHandler) -> +authorize_api_key(LogicHandler, OperationID, From, KeyParam, Req0) -> {ApiKey, Req} = get_api_key(From, KeyParam, Req0), case ApiKey of undefined -> AuthHeader = <<"">>, {false, AuthHeader, Req}; _ -> - case LogicHandler:authorize_api_key(ApiKey, OperationID) of + Result = {{packageName}}_logic_handler:authorize_api_key( + LogicHandler, + OperationID, + ApiKey + ), + case Result of {true, Context} -> {true, Context, Req}; false -> @@ -28,12 +33,18 @@ authorize_api_key(From, KeyParam, OperationID, Req0, LogicHandler) -> end. get_api_key(header, KeyParam, Req0) -> - {Headers, Req} = cowboy_req:headers(Req0), - {swagger_utils:get_opt({{packageName}}_utils:to_header(KeyParam), Headers), Req}; + {Headers, Req} = cowboy_req:headers(Req0), + { + swagger_utils:get_opt( + {{packageName}}_utils:to_header(KeyParam), + Headers + ), + Req + }; get_api_key(qs_val, KeyParam, Req0) -> - {QS, Req} = cowboy_req:qs_vals(Req0), - {swagger_utils:get_opt(KeyParam, QS), Req}. + {QS, Req} = cowboy_req:qs_vals(Req0), + {swagger_utils:get_opt(KeyParam, QS), Req}. diff --git a/modules/swagger-codegen/src/main/resources/erlang-server/default_logic_handler.mustache b/modules/swagger-codegen/src/main/resources/erlang-server/default_logic_handler.mustache index 2444ee31e03..3be26911c74 100644 --- a/modules/swagger-codegen/src/main/resources/erlang-server/default_logic_handler.mustache +++ b/modules/swagger-codegen/src/main/resources/erlang-server/default_logic_handler.mustache @@ -11,16 +11,22 @@ {{#authMethods}} {{#isApiKey}} --spec authorize_api_key(ApiKey :: binary(), OperationID :: atom()) -> {true, #{}}. +-spec authorize_api_key(OperationID :: {{packageName}}_api:operation_id(), ApiKey :: binary()) -> {true, #{}}. authorize_api_key(_, _) -> {true, #{}}. {{/isApiKey}} {{/authMethods}} --spec handle_request(OperationID :: atom(), Req :: cowboy_req:req(), Context :: #{}) --> {Code :: integer(), Headers :: [], Body :: binary()}. +-spec handle_request( + OperationID :: {{packageName}}_api:operation_id(), + Req :: cowboy_req:req(), + Context :: #{} +) -> + {Status :: cowboy:http_status(), Headers :: cowboy:http_headers(), Body :: #{}}. handle_request(OperationID, Req, Context) -> - Message = io_lib:format("Got not implemented request to process: ~p~n", [{OperationID, Req, Context}]), - error_logger:info_msg(Message), - {501, [], <<"">>}. + error_logger:error_msg( + "Got not implemented request to process: ~p~n", + [{OperationID, Req, Context}] + ), + {501, [], #{}}. diff --git a/modules/swagger-codegen/src/main/resources/erlang-server/handler.mustache b/modules/swagger-codegen/src/main/resources/erlang-server/handler.mustache index 8a93cab7d11..4559bc2962a 100644 --- a/modules/swagger-codegen/src/main/resources/erlang-server/handler.mustache +++ b/modules/swagger-codegen/src/main/resources/erlang-server/handler.mustache @@ -19,29 +19,28 @@ -export([handle_request_json/2]). -record(state, { - operation_id :: atom(), + operation_id :: {{packageName}}_api:operation_id(), logic_handler :: atom(), validator_state :: jesse_state:state(), context=#{} :: #{} }). --type init_opts() :: [any()]. +-type state() :: state(). --spec init(TransportName :: atom(), Req :: cowboy_req:req(), Opts :: init_opts()) --> {upgrade, protocol, cowboy_rest, Req :: cowboy_req:req(), Opts :: init_opts()}. +-spec init(TransportName :: atom(), Req :: cowboy_req:req(), Opts :: {{packageName}}_router:init_opts()) -> + {upgrade, protocol, cowboy_rest, Req :: cowboy_req:req(), Opts :: {{packageName}}_router:init_opts()}. init(_Transport, Req, Opts) -> {upgrade, protocol, cowboy_rest, Req, Opts}. --spec rest_init(Req :: cowboy_req:req(), Opts :: init_opts()) --> {ok, Req :: cowboy_req:req(), State :: #state{}}. +-spec rest_init(Req :: cowboy_req:req(), Opts :: {{packageName}}_router:init_opts()) -> + {ok, Req :: cowboy_req:req(), State :: state()}. -rest_init(Req0, [Operations, LogicHandler, ValidatorState]) -> +rest_init(Req0, {Operations, LogicHandler, ValidatorState}) -> {Method, Req} = cowboy_req:method(Req0), OperationID = maps:get(Method, Operations, undefined), - Message = io_lib:format("Attempt to process operation: ~p", [OperationID]), - report(info, Message), + error_logger:info_msg("Attempt to process operation: ~p", [OperationID]), State = #state{ operation_id = OperationID, @@ -50,24 +49,46 @@ rest_init(Req0, [Operations, LogicHandler, ValidatorState]) -> }, {ok, Req, State}. --spec allowed_methods(Req :: cowboy_req:req(), State :: #state{}) --> {Value :: any(), Req :: cowboy_req:req(), State :: #state{}}. +-spec allowed_methods(Req :: cowboy_req:req(), State :: state()) -> + {Value :: [binary()], Req :: cowboy_req:req(), State :: state()}. {{#operations}}{{#operation}} -allowed_methods(Req, State = #state{operation_id = '{{operationId}}'}) -> +allowed_methods( + Req, + State = #state{ + operation_id = '{{operationId}}' + } +) -> {[<<"{{httpMethod}}">>], Req, State}; {{/operation}}{{/operations}} allowed_methods(Req, State) -> {[], Req, State}. --spec is_authorized(Req :: cowboy_req:req(), State :: #state{}) --> {Value :: any(), Req :: cowboy_req:req(), State :: #state{}}. +-spec is_authorized(Req :: cowboy_req:req(), State :: state()) -> + { + Value :: true | {false, AuthHeader :: iodata()}, + Req :: cowboy_req:req(), + State :: state() + }. {{#operations}}{{#operation}} -is_authorized(Req0, State = #state{operation_id = '{{operationId}}' = OperationID, logic_handler = LogicHandler}) -> +is_authorized( + Req0, + State = #state{ + operation_id = '{{operationId}}' = OperationID, + logic_handler = LogicHandler + } +) -> {{#authMethods}} {{#isApiKey}} From = {{#isKeyInQuery}}qs_val{{/isKeyInQuery}}{{#isKeyInHeader}}header{{/isKeyInHeader}}, - case {{packageName}}_auth:authorize_api_key(From, "{{keyParamName}}", OperationID, Req0, LogicHandler) of + Result = {{packageName}}_auth:authorize_api_key( + LogicHandler, + OperationID, + From, + "{{keyParamName}}", + Req0 + ), + case Result of {true, Context, Req} -> {true, Req, State#state{context = Context}}; {false, AuthHeader, Req} -> {{false, AuthHeader}, Req, State} end; @@ -77,17 +98,27 @@ is_authorized(Req0, State = #state{operation_id = '{{operationId}}' = OperationI is_authorized(Req, State) -> {{false, <<"">>}, Req, State}. --spec content_types_accepted(Req :: cowboy_req:req(), State :: #state{}) --> {Value :: any(), Req :: cowboy_req:req(), State :: #state{}}. +-spec content_types_accepted(Req :: cowboy_req:req(), State :: state()) -> + { + Value :: [{binary(), AcceptResource :: atom()}], + Req :: cowboy_req:req(), + State :: state() + }. + content_types_accepted(Req, State) -> {[ {<<"application/json">>, handle_request_json} ], Req, State}. --spec valid_content_headers(Req :: cowboy_req:req(), State :: #state{}) --> {Value :: any(), Req :: cowboy_req:req(), State :: #state{}}. +-spec valid_content_headers(Req :: cowboy_req:req(), State :: state()) -> + {Value :: boolean(), Req :: cowboy_req:req(), State :: state()}. {{#operations}}{{#operation}} -valid_content_headers(Req0, State = #state{operation_id = '{{operationId}}'}) -> +valid_content_headers( + Req0, + State = #state{ + operation_id = '{{operationId}}' + } +) -> Headers = [{{#headerParams}}"{{baseName}}"{{#hasMore}},{{/hasMore}}{{/headerParams}}], {Result, Req} = validate_headers(Headers, Req0), {Result, Req, State}; @@ -95,40 +126,44 @@ valid_content_headers(Req0, State = #state{operation_id = '{{operationId}}'}) -> valid_content_headers(Req, State) -> {false, Req, State}. --spec content_types_provided(Req :: cowboy_req:req(), State :: #state{}) --> {Value :: any(), Req :: cowboy_req:req(), State :: #state{}}. +-spec content_types_provided(Req :: cowboy_req:req(), State :: state()) -> + { + Value :: [{binary(), ProvideResource :: atom()}], + Req :: cowboy_req:req(), + State :: state() + }. content_types_provided(Req, State) -> {[ {<<"application/json">>, handle_request_json} ], Req, State}. --spec malformed_request(Req :: cowboy_req:req(), State :: #state{}) --> {Value :: any(), Req :: cowboy_req:req(), State :: #state{}}. +-spec malformed_request(Req :: cowboy_req:req(), State :: state()) -> + {Value :: false, Req :: cowboy_req:req(), State :: state()}. malformed_request(Req, State) -> {false, Req, State}. --spec allow_missing_post(Req :: cowboy_req:req(), State :: #state{}) --> {Value :: any(), Req :: cowboy_req:req(), State :: #state{}}. +-spec allow_missing_post(Req :: cowboy_req:req(), State :: state()) -> + {Value :: false, Req :: cowboy_req:req(), State :: state()}. allow_missing_post(Req, State) -> {false, Req, State}. --spec delete_resource(Req :: cowboy_req:req(), State :: #state{}) --> {Value :: any(), Req :: cowboy_req:req(), State :: #state{}}. +-spec delete_resource(Req :: cowboy_req:req(), State :: state()) -> + processed_response(). delete_resource(Req, State) -> handle_request_json(Req, State). --spec known_content_type(Req :: cowboy_req:req(), State :: #state{}) --> {Value :: any(), Req :: cowboy_req:req(), State :: #state{}}. +-spec known_content_type(Req :: cowboy_req:req(), State :: state()) -> + {Value :: true, Req :: cowboy_req:req(), State :: state()}. known_content_type(Req, State) -> {true, Req, State}. --spec valid_entity_length(Req :: cowboy_req:req(), State :: #state{}) --> {Value :: any(), Req :: cowboy_req:req(), State :: #state{}}. +-spec valid_entity_length(Req :: cowboy_req:req(), State :: state()) -> + {Value :: true, Req :: cowboy_req:req(), State :: state()}. valid_entity_length(Req, State) -> %% @TODO check the length @@ -136,12 +171,17 @@ valid_entity_length(Req, State) -> %%%% --type handler_response() :: - {ok, {Status :: cowboy:http_status(), Headers :: cowboy:http_headers(), Body :: binary()}} | - {error, Reason :: any()}. +-type result_ok() :: { + ok, + {Status :: cowboy:http_status(), Headers :: cowboy:http_headers(), Body :: iodata()} +}. --spec process_response(Response :: handler_response(), cowboy_req:req(), #state{}) -> {halt, cowboy_req:req(), #state{}}. +-type result_error() :: {error, Reason :: any()}. +-type processed_response() :: {halt, cowboy_req:req(), state()}. + +-spec process_response(result_ok() | result_error(), cowboy_req:req(), state()) -> + processed_response(). process_response(Response, Req0, State = #state{operation_id = OperationID}) -> case Response of @@ -149,14 +189,13 @@ process_response(Response, Req0, State = #state{operation_id = OperationID}) -> {ok, Req} = cowboy_req:reply(Code, Headers, Body, Req0), {halt, Req, State}; {error, Message} -> - Reason = io_lib:format("Unable to process request for ~p: ~p", [OperationID, Message]), - report(error, Reason), + error_logger:error_msg("Unable to process request for ~p: ~p", [OperationID, Message]), {ok, Req} = cowboy_req:reply(400, Req0), {halt, Req, State} end. --spec handle_request_json(cowboy_req:req(), #state{}) -> {halt, cowboy_req:req(), #state{}}. +-spec handle_request_json(cowboy_req:req(), state()) -> {halt, cowboy_req:req(), state()}. handle_request_json( Req0, @@ -169,23 +208,23 @@ handle_request_json( ) -> case {{packageName}}_api:populate_request(OperationID, Req0, ValidatorState) of {ok, Populated, Req1} -> - case LogicHandler:handle_request(OperationID, Populated, Context) of - {Code, Headers, Body} -> - {{packageName}}_api:validate_response(OperationID, Code, Body , ValidatorState), - PreparedBody = jsx:encode(Body), - Response = {ok, {Code, Headers, PreparedBody}}, - process_response(Response, Req1, State) - end; + {Code, Headers, Body} = {{packageName}}_logic_handler:handle_request( + LogicHandler, + OperationID, + Populated, + Context + ), + _ = {{packageName}}_api:validate_response( + OperationID, + Code, + Body, + ValidatorState + ), + PreparedBody = jsx:encode(Body), + Response = {ok, {Code, Headers, PreparedBody}}, + process_response(Response, Req1, State); {error, Reason, Req1} -> process_response({error, Reason}, Req1, State) end. validate_headers(_, Req) -> {true, Req}. - --spec report(Level :: error | info, Message :: iodata()) -> ok. - -report(info, Message) -> - error_logger:info_msg(Message); - -report(error, Message) -> - error_logger:error_msg(Message). diff --git a/modules/swagger-codegen/src/main/resources/erlang-server/logic_handler.mustache b/modules/swagger-codegen/src/main/resources/erlang-server/logic_handler.mustache index da1d1b516f9..1d1399b4b9c 100644 --- a/modules/swagger-codegen/src/main/resources/erlang-server/logic_handler.mustache +++ b/modules/swagger-codegen/src/main/resources/erlang-server/logic_handler.mustache @@ -1,12 +1,50 @@ -module({{packageName}}_logic_handler). +-export([handle_request/4]). +{{#authMethods}} + {{#isApiKey}} +-export([authorize_api_key/3]). + {{/isApiKey}} +{{/authMethods}} -type context() :: #{binary() => any()}. +-type handler_response() ::{ + Status :: cowboy:http_status(), + Headers :: cowboy:http_headers(), + Body :: #{} +}. + +-export_type([handler_response/0]). {{#authMethods}} {{#isApiKey}} --callback authorize_api_key(ApiKey :: binary(), OperationID :: atom()) -> Result :: boolean() | {boolean(), context()}. +-callback authorize_api_key( + OperationID :: {{packageName}}_api:operation_id(), + ApiKey :: binary() +) -> + Result :: boolean() | {boolean(), context()}. {{/isApiKey}} {{/authMethods}} --callback handle_request(OperationID :: atom(), Request :: any(), Context :: context()) -> {Status :: integer(), [Header :: binary()], Body :: any()}. +-callback handle_request(OperationID :: {{packageName}}_api:operation_id(), Request :: any(), Context :: context()) -> + handler_response(). + +-spec handle_request( + Handler :: atom(), + OperationID :: {{packageName}}_api:operation_id(), + Request :: any(), + Context :: context() +) -> + handler_response(). + +handle_request(Handler, OperationID, Req, Context) -> + Handler:handle_request(OperationID, Req, Context). + +{{#authMethods}} + {{#isApiKey}} +-spec authorize_api_key(Handler :: atom(), OperationID :: {{packageName}}_api:operation_id(), ApiKey :: binary()) -> + Result :: boolean() | {boolean(), context()}. +authorize_api_key(Handler, OperationID, ApiKey) -> + Handler:authorize_api_key(OperationID, ApiKey). + {{/isApiKey}} +{{/authMethods}} diff --git a/modules/swagger-codegen/src/main/resources/erlang-server/router.mustache b/modules/swagger-codegen/src/main/resources/erlang-server/router.mustache index cb71fcc629a..9c5ff89b229 100644 --- a/modules/swagger-codegen/src/main/resources/erlang-server/router.mustache +++ b/modules/swagger-codegen/src/main/resources/erlang-server/router.mustache @@ -2,7 +2,23 @@ -export([get_paths/1]). --spec get_paths(LogicHandler :: atom()) -> [{'_',[any()]},...]. +-type operations() :: #{ + Method :: binary() => {{packageName}}_api:operation_id() +}. + +-type init_opts() :: { + Operations :: operations(), + LogicHandler :: atom(), + ValidatorState :: jesse_state:state() +}. + +-export_type([init_opts/0]). + +-spec get_paths(LogicHandler :: atom()) -> [{'_',[{ + Path :: string(), + Handler :: atom(), + InitOpts :: init_opts() +}]}]. get_paths(LogicHandler) -> ValidatorState = prepare_validator(), @@ -15,7 +31,7 @@ get_paths(LogicHandler) -> ), [ {'_', - [{P, H, [O, LogicHandler, ValidatorState]} || {P, H, O} <- PreparedPaths] + [{P, H, {O, LogicHandler, ValidatorState}} || {P, H, O} <- PreparedPaths] } ]. From c642c9296d5ba9836668b110f19eca3669c20e89 Mon Sep 17 00:00:00 2001 From: Artem Ocheredko Date: Wed, 31 Aug 2016 13:15:18 +0300 Subject: [PATCH 4/5] CAPI-23 Fix codegen function name, add some specs --- .../src/main/resources/erlang-server/api.mustache | 7 ++++--- .../src/main/resources/erlang-server/auth.mustache | 2 +- .../main/resources/erlang-server/logic_handler.mustache | 2 +- 3 files changed, 6 insertions(+), 5 deletions(-) diff --git a/modules/swagger-codegen/src/main/resources/erlang-server/api.mustache b/modules/swagger-codegen/src/main/resources/erlang-server/api.mustache index 91c8a374e7c..4d8108b9811 100644 --- a/modules/swagger-codegen/src/main/resources/erlang-server/api.mustache +++ b/modules/swagger-codegen/src/main/resources/erlang-server/api.mustache @@ -6,10 +6,11 @@ -export([validate_response/4]). -type operation_id() :: atom(). +-type request_param() :: atom(). -export_type([operation_id/0]). --spec request_params(OperationID :: operation_id()) -> [Param :: atom()]. +-spec request_params(OperationID :: operation_id()) -> [Param :: request_param()]. {{#apiInfo}}{{#apis}} {{#operations}}{{#operation}} request_params('{{operationId}}') -> @@ -41,7 +42,7 @@ request_params(_) -> required | not_required. --spec request_param_info(OperationID :: operation_id(), Name :: atom()) -> #{ +-spec request_param_info(OperationID :: operation_id(), Name :: request_param()) -> #{ source => qs_val | binding | header | body, rules => [rule()] }. @@ -113,7 +114,7 @@ populate_request_param(OperationID, Name, Req0, ValidatorState) -> -spec validate_response( OperationID :: operation_id(), - Code :: integer(), + Code :: non_neg_integer(), Body :: jesse:json_term(), ValidatorState :: jesse_state:state() ) -> ok | no_return(). diff --git a/modules/swagger-codegen/src/main/resources/erlang-server/auth.mustache b/modules/swagger-codegen/src/main/resources/erlang-server/auth.mustache index b0555359e3c..c0d4091435b 100644 --- a/modules/swagger-codegen/src/main/resources/erlang-server/auth.mustache +++ b/modules/swagger-codegen/src/main/resources/erlang-server/auth.mustache @@ -44,7 +44,7 @@ get_api_key(header, KeyParam, Req0) -> get_api_key(qs_val, KeyParam, Req0) -> {QS, Req} = cowboy_req:qs_vals(Req0), - {swagger_utils:get_opt(KeyParam, QS), Req}. + { {{packageName}}_utils:get_opt(KeyParam, QS), Req}. diff --git a/modules/swagger-codegen/src/main/resources/erlang-server/logic_handler.mustache b/modules/swagger-codegen/src/main/resources/erlang-server/logic_handler.mustache index 1d1399b4b9c..cb4ba201bf4 100644 --- a/modules/swagger-codegen/src/main/resources/erlang-server/logic_handler.mustache +++ b/modules/swagger-codegen/src/main/resources/erlang-server/logic_handler.mustache @@ -43,7 +43,7 @@ handle_request(Handler, OperationID, Req, Context) -> {{#authMethods}} {{#isApiKey}} -spec authorize_api_key(Handler :: atom(), OperationID :: {{packageName}}_api:operation_id(), ApiKey :: binary()) -> - Result :: boolean() | {boolean(), context()}. + Result :: false | {true, context()}. authorize_api_key(Handler, OperationID, ApiKey) -> Handler:authorize_api_key(OperationID, ApiKey). {{/isApiKey}} From 855053b141d78d71e3b2bf54c0fa92eb4582b9cd Mon Sep 17 00:00:00 2001 From: Artem Ocheredko Date: Wed, 31 Aug 2016 20:26:43 +0300 Subject: [PATCH 5/5] CAPI-23 Add proper formatting in auth module. Limit http code range in specs --- .../main/resources/erlang-server/api.mustache | 2 +- .../resources/erlang-server/auth.mustache | 70 +++++++++---------- 2 files changed, 36 insertions(+), 36 deletions(-) diff --git a/modules/swagger-codegen/src/main/resources/erlang-server/api.mustache b/modules/swagger-codegen/src/main/resources/erlang-server/api.mustache index 4d8108b9811..355cfad6dae 100644 --- a/modules/swagger-codegen/src/main/resources/erlang-server/api.mustache +++ b/modules/swagger-codegen/src/main/resources/erlang-server/api.mustache @@ -114,7 +114,7 @@ populate_request_param(OperationID, Name, Req0, ValidatorState) -> -spec validate_response( OperationID :: operation_id(), - Code :: non_neg_integer(), + Code :: 200..599, Body :: jesse:json_term(), ValidatorState :: jesse_state:state() ) -> ok | no_return(). diff --git a/modules/swagger-codegen/src/main/resources/erlang-server/auth.mustache b/modules/swagger-codegen/src/main/resources/erlang-server/auth.mustache index c0d4091435b..2fd7bd8652c 100644 --- a/modules/swagger-codegen/src/main/resources/erlang-server/auth.mustache +++ b/modules/swagger-codegen/src/main/resources/erlang-server/auth.mustache @@ -3,48 +3,48 @@ -export([authorize_api_key/5]). -spec authorize_api_key( - LogicHandler :: atom(), - OperationID :: {{packageName}}_api:operation_id(), - From :: header | qs_val, - KeyParam :: iodata() | atom(), - Req ::cowboy_req:req() + LogicHandler :: atom(), + OperationID :: {{packageName}}_api:operation_id(), + From :: header | qs_val, + KeyParam :: iodata() | atom(), + Req ::cowboy_req:req() )-> {true, Context :: #{binary() => any()}, Req ::cowboy_req:req()} | - {false, AuthHeader :: binary(), Req ::cowboy_req:req()}. + {false, AuthHeader :: binary(), Req ::cowboy_req:req()}. authorize_api_key(LogicHandler, OperationID, From, KeyParam, Req0) -> - {ApiKey, Req} = get_api_key(From, KeyParam, Req0), - case ApiKey of - undefined -> - AuthHeader = <<"">>, - {false, AuthHeader, Req}; - _ -> - Result = {{packageName}}_logic_handler:authorize_api_key( - LogicHandler, - OperationID, - ApiKey - ), - case Result of - {true, Context} -> - {true, Context, Req}; - false -> - AuthHeader = <<"">>, - {false, AuthHeader, Req} - end - end. + {ApiKey, Req} = get_api_key(From, KeyParam, Req0), + case ApiKey of + undefined -> + AuthHeader = <<"">>, + {false, AuthHeader, Req}; + _ -> + Result = {{packageName}}_logic_handler:authorize_api_key( + LogicHandler, + OperationID, + ApiKey + ), + case Result of + {true, Context} -> + true, Context, Req}; + false -> + AuthHeader = <<"">>, + {false, AuthHeader, Req} + end + end. get_api_key(header, KeyParam, Req0) -> - {Headers, Req} = cowboy_req:headers(Req0), - { - swagger_utils:get_opt( - {{packageName}}_utils:to_header(KeyParam), - Headers - ), - Req - }; + {Headers, Req} = cowboy_req:headers(Req0), + { + swagger_utils:get_opt( + {{packageName}}_utils:to_header(KeyParam), + Headers + ), + Req + }; get_api_key(qs_val, KeyParam, Req0) -> - {QS, Req} = cowboy_req:qs_vals(Req0), - { {{packageName}}_utils:get_opt(KeyParam, QS), Req}. + {QS, Req} = cowboy_req:qs_vals(Req0), + { {{packageName}}_utils:get_opt(KeyParam, QS), Req}.