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..355cfad6dae 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,12 @@ -export([populate_request/3]). -export([validate_response/4]). +-type operation_id() :: atom(). +-type request_param() :: atom(). +-export_type([operation_id/0]). + +-spec request_params(OperationID :: operation_id()) -> [Param :: request_param()]. {{#apiInfo}}{{#apis}} {{#operations}}{{#operation}} request_params('{{operationId}}') -> @@ -17,31 +22,56 @@ request_params('{{operationId}}') -> request_params(_) -> error(unknown_operation). +-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 :: request_param()) -> #{ + source => qs_val | binding | header | body, + rules => [rule()] +}. + {{#apiInfo}}{{#apis}} {{#operations}}{{#operation}}{{#allParams}} request_param_info('{{operationId}}', {{^isBodyParam}}'{{baseName}}'{{/isBodyParam}}{{#isBodyParam}}'{{dataType}}'{{/isBodyParam}}) -> #{ 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}} ] @@ -50,6 +80,14 @@ request_param_info('{{operationId}}', {{^isBodyParam}}'{{baseName}}'{{/isBodyPar request_param_info(OperationID, Name) -> error({unknown_param, OperationID, Name}). +-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), populate_request_params(OperationID, Params, Req, ValidatorState, #{}). @@ -74,7 +112,12 @@ populate_request_param(OperationID, Name, Req0, ValidatorState) -> {error, Reason, Req} end. - +-spec validate_response( + OperationID :: operation_id(), + Code :: 200..599, + Body :: jesse:json_term(), + ValidatorState :: jesse_state:state() +) -> ok | no_return(). {{#apiInfo}}{{#apis}} {{#operations}}{{#operation}} {{#responses}} @@ -86,12 +129,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) @@ -101,7 +138,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 @@ -110,35 +147,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 -> - validation_error(Rule, {Name, Error}) + 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 @@ -150,19 +187,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 @@ -174,65 +211,84 @@ 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), + _ = 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. +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(). + +validation_error(ViolatedRule, Name) -> + validation_error(ViolatedRule, Name, #{}). + +-spec validation_error(Rule :: any(), Name :: any(), Info :: #{}) -> no_return(). -validation_error(Name, Violated) -> - throw({wrong_param, Name, Violated}). +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/auth.mustache b/modules/swagger-codegen/src/main/resources/erlang-server/auth.mustache index 624e86cf064..2fd7bd8652c 100644 --- a/modules/swagger-codegen/src/main/resources/erlang-server/auth.mustache +++ b/modules/swagger-codegen/src/main/resources/erlang-server/auth.mustache @@ -2,29 +2,49 @@ -export([authorize_api_key/5]). -authorize_api_key(From, KeyParam, OperationID, Req0, LogicHandler) -> - {ApiKey, Req} = get_api_key(From, KeyParam, Req0), - case ApiKey of - undefined -> - AuthHeader = <<"">>, - {false, AuthHeader, Req}; - _ -> - case LogicHandler:authorize_api_key(ApiKey, OperationID) of - {true, Context} -> - {true, Context, Req}; - false -> - AuthHeader = <<"">>, - {false, AuthHeader, Req} - end - end. +-spec authorize_api_key( + 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()}. + +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. get_api_key(header, KeyParam, Req0) -> {Headers, Req} = cowboy_req:headers(Req0), - {swagger_utils:get_opt({{packageName}}_utils:to_header(KeyParam), Headers), Req}; + { + 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}. + { {{packageName}}_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 f42bdc04092..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,10 +11,22 @@ {{#authMethods}} {{#isApiKey}} +-spec authorize_api_key(OperationID :: {{packageName}}_api:operation_id(), ApiKey :: binary()) -> {true, #{}}. + authorize_api_key(_, _) -> {true, #{}}. {{/isApiKey}} {{/authMethods}} +-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) -> - io:format(user, "Got request to process: ~p~n", [{OperationID, Req, Context}]), - {501, [], <<"Not Implemented">>}. + 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 db72b2739b4..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,18 +19,29 @@ -export([handle_request_json/2]). -record(state, { - operation_id, - logic_handler, - validator_state, - context=#{} + operation_id :: {{packageName}}_api:operation_id(), + logic_handler :: atom(), + validator_state :: jesse_state:state(), + context=#{} :: #{} }). +-type state() :: state(). + +-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}. -rest_init(Req0, [Operations, LogicHandler, ValidatorState]) -> +-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}) -> {Method, Req} = cowboy_req:method(Req0), OperationID = maps:get(Method, Operations, undefined), + + error_logger:info_msg("Attempt to process operation: ~p", [OperationID]), + State = #state{ operation_id = OperationID, logic_handler = LogicHandler, @@ -38,19 +49,46 @@ rest_init(Req0, [Operations, LogicHandler, ValidatorState]) -> }, {ok, Req, 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 :: 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; @@ -60,13 +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 :: [{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 :: 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}; @@ -74,28 +126,77 @@ 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 :: [{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 :: 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 :: false, Req :: cowboy_req:req(), State :: state()}. + allow_missing_post(Req, State) -> {false, Req, 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 :: 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 :: true, Req :: cowboy_req:req(), State :: state()}. + valid_entity_length(Req, State) -> %% @TODO check the length {true, Req, State}. %%%% + +-type result_ok() :: { + ok, + {Status :: cowboy:http_status(), Headers :: cowboy:http_headers(), Body :: iodata()} +}. + +-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 + {ok, {Code, Headers, Body}} -> + {ok, Req} = cowboy_req:reply(Code, Headers, Body, Req0), + {halt, Req, State}; + {error, Message} -> + 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()}. + handle_request_json( Req0, State = #state{ @@ -107,15 +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), - {ok, Req} = cowboy_req:reply(Code, Headers, PreparedBody, Req1), - {halt, Req, State} - end; - {error, _Reason, Req1} -> - {false, Req1, State} + {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}. 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..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 @@ -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 :: false | {true, 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 55755ad0a9a..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,6 +2,24 @@ -export([get_paths/1]). +-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(), PreparedPaths = maps:fold( @@ -13,7 +31,7 @@ get_paths(LogicHandler) -> ), [ {'_', - [{P, H, [O, LogicHandler, ValidatorState]} || {P, H, O} <- PreparedPaths] + [{P, H, {O, LogicHandler, ValidatorState}} || {P, H, O} <- PreparedPaths] } ]. 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;