Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -119,7 +119,6 @@ public void processOpts() {
supportingFiles.add(new SupportingFile("utils.mustache", "", toSourceFilePath("utils", "erl")));
supportingFiles.add(new SupportingFile("types.mustache", "", toPackageNameSrcFile("erl")));
supportingFiles.add(new SupportingFile("handler_api.mustache", "", toSourceFilePath("handler_api", "erl")));
supportingFiles.add(new SupportingFile("logic_handler.mustache", "", toSourceFilePath("logic_handler", "erl")));
supportingFiles.add(new SupportingFile("validation.mustache", "", toSourceFilePath("validation", "erl")));
supportingFiles.add(new SupportingFile("param_validator.mustache", "", toSourceFilePath("param_validator", "erl")));
supportingFiles.add(new SupportingFile("schema_validator.mustache", "", toSourceFilePath("schema_validator", "erl")));
Expand Down Expand Up @@ -221,11 +220,11 @@ public String toModelName(String name) {
public String toOperationId(String operationId) {
// method name cannot use reserved keyword, e.g. return
if (isReservedWord(operationId)) {
LOGGER.warn(operationId + " (reserved word) cannot be used as method name. Renamed to " + camelize(sanitizeName("call_" + operationId)));
LOGGER.warn(operationId + " (reserved word) cannot be used as method name. Renamed to " + underscore(sanitizeName("call_" + operationId)));
operationId = "call_" + operationId;
}

return camelize(operationId);
return underscore(operationId);
}

@Override
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
{{^isContainer}}{{#isString}}binary(){{/isString}}{{#isInteger}}integer(){{/isInteger}}{{#isLong}}integer(){{/isLong}}{{#isFloat}}float(){{/isFloat}}{{#isDouble}}float(){{/isDouble}}{{#isByteArray}}binary(){{/isByteArray}}{{#isBinary}}binary(){{/isBinary}}{{#isBoolean}}boolean(){{/isBoolean}}{{#isDate}}binary(){{/isDate}}{{#isDateTime}}binary(){{/isDateTime}}{{#isEnum}}{{#allowableValues}}{{#values}}'{{.}}'{{^-last}} | {{/-last}}{{/values}}{{/allowableValues}}{{/isEnum}}{{/isContainer}}
Original file line number Diff line number Diff line change
Expand Up @@ -21,9 +21,30 @@
%% Handlers
-export([handle_request_json/2]).

{{#operations}}{{#operation}}{{#authMethods}}{{#isApiKey}}
-callback authorize_api_key
(OperationID :: {{operationID}}, ApiKey :: {{packageName}}:api_key(), Opts :: undefined | term()) -> {{packageName}}::auth_result();
{{/isApiKey}}{{/authMethods}}{{/operation}}{{/operations}}
(_, _) -> true.

%% Handler behaviour definition
{{#operations}}{{#operation}}
-callback {{operationId}}(Request, Context) ->
{ok | error, {Code, Headers, Body}}
when
Request :: #{
{{#allParams}} {{^isBodyParam}}'{{baseName}}'{{/isBodyParam}}{{#isBodyParam}}'{{dataType}}'{{/isBodyParam}} {{#required}}:={{/required}}{{^required}}=>{{/required}} {{#isListContainer}}[{{^isBodyParam}}{{>api.type_spec}}{{/isBodyParam}}{{#isBodyParam}}{{packageName}}:body_schema(){{/isBodyParam}}]{{/isListContainer}}{{^isListContainer}}{{^isBodyParam}}{{>api.type_spec}}{{/isBodyParam}}{{#isBodyParam}}{{packageName}}:body_schema(){{/isBodyParam}}{{/isListContainer}}{{^hasMore}}{{/hasMore}}{{#hasMore}},{{/hasMore}}
{{/allParams}}
},
Context :: {{packageName}}:request_context(),
Code :: {{#responses}}{{code}}{{#hasMore}} | {{/hasMore}}{{/responses}},
Headers :: cowboy:http_headers(),
Body :: {{packageName}}:body_schema() | [{{packageName}}:body_schema()] | undefined.
{{/operation}}{{/operations}}

-record(state, {
operation_id :: {{packageName}}:operation_id(),
logic_handler :: module(),
logic_handler :: {{packageName}}_router:handeler(),
context :: {{packageName}}:request_context()
}).

Expand Down Expand Up @@ -77,39 +98,18 @@ allowed_methods(Req, State) ->
Req :: cowboy_req:req(),
State :: state()
}.
{{#operations}}{{#operation}}
{{#operations}}{{#operation}}{{#authMethods}}{{#isApiKey}}
is_authorized(
Req0,
State = #state{
operation_id = '{{operationId}}' = OperationID,
logic_handler = LogicHandler,
context = Context
operation_id = '{{operationId}}' = OperationID
}
) ->
{{#authMethods}}
{{#isApiKey}}
From = {{#isKeyInQuery}}qs_val{{/isKeyInQuery}}{{#isKeyInHeader}}header{{/isKeyInHeader}},
Result = {{packageName}}_handler_api:authorize_api_key(
LogicHandler,
OperationID,
From,
'{{keyParamName}}',
Req0
),
case Result of
{true, AuthContext, Req} ->
NewContext = Context#{
auth_context => AuthContext
},
{true, Req, State#state{context = NewContext}};
{false, AuthHeader, Req} ->
{{false, AuthHeader}, Req, State}
end;
{{/isApiKey}}
{{/authMethods}}
{{/operation}}{{/operations}}
authorize_api_key({{packageName}}_handler_api:get_api_key(From, '{{keyParamName}}', Req0));
{{/isApiKey}}{{/authMethods}}{{/operation}}{{/operations}}
is_authorized(Req, State) ->
{{false, <<"">>}, Req, State}.
handle_auth_result(false, Req, State).

-spec content_types_accepted(Req :: cowboy_req:req(), State :: state()) ->
{
Expand Down Expand Up @@ -222,12 +222,26 @@ handle_request_json(


%% Internal
authorize_api_key({undefined, Req}, State) ->
handle_auth_result(false, Req, State);
authorize_api_key({ApiKey, Req}, State = #state{
operation_id = OperationID,
logic_handler = LogicHandler
}) ->
{Handler, Opts} = {{packageName}}_utils:get_mod_opts(LogicHandler),
handle_auth_result(Handler:authorize_api_key(OperationID, ApiKey, Opts), Req, State).

handle_auth_result(false, Req, State) ->
{{false, <<>>}, Req, State};
handle_auth_result({true, AuthContext}, Req, State = #state{context = Context}) ->
{true, Req, State#state{context = Context#{auth_context => AuthContext}}}.

populate_request(OperationID, Req) ->
{{packageName}}_handler_api:populate_request(get_request_spec(OperationID), Req).

handle_request(LogicHandler, OperationID, Populated, Context) ->
{{packageName}}_logic_handler:handle_request(LogicHandler, OperationID, Populated, Context).
{Handler, Opts} = {{packageName}}_utils:get_mod_opts(LogicHandler),
Handler:OperationID(Populated, Context).

validate_response(error, _, _) ->
ok;
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
%% -*- mode: erlang -*-
-module({{packageName}}_handler_api).

-export([authorize_api_key/5]).
-export([get_api_key/5]).
-export([determine_peer/1]).
-export([populate_request/2]).
-export([validate_response/2]).
Expand Down Expand Up @@ -30,35 +30,22 @@

%% API

-spec authorize_api_key(
LogicHandler :: module(),
OperationID :: {{packageName}}:operation_id(),
-spec get_api_key(
From :: header | qs_val,
KeyParam :: iodata() | atom(),
Req :: cowboy_req:req()
)->
{true, Context :: {{packageName}}:auth_context(), Req ::cowboy_req:req()} |
{false, AuthHeader :: binary(), Req ::cowboy_req:req()}.
) ->
{\{{packageName}}:api_key(), Req :: cowboy_req:req()} |
{undefined , Req :: cowboy_req:req()}.

authorize_api_key(LogicHandler, OperationID, From, KeyParam, Req0) ->
get_api_key(From, KeyParam, Req0) ->
{ok, ApiKey, Req} = get_value(From, KeyParam, Req0),
case ApiKey of
undefined ->
AuthHeader = <<"">>,
{false, AuthHeader, Req};
{undefined, 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
{ApiKey, Req}
end.

-spec determine_peer(Req :: cowboy_req:req()) ->
Expand All @@ -73,15 +60,15 @@ determine_peer(Req) ->
{determine_peer_from_header(Value, Peer), Req2}.

-spec populate_request(Spec :: request_spec(), Req :: cowboy_req:req()) ->
{ok, Populated :: {{packageName}}:object(), Req :: cowboy_req:req()} |
{ok, Populated :: {{packageName}}:object() , Req :: cowboy_req:req()} |
{error, Message :: {{packageName}}:error_reason(), Req :: cowboy_req:req()}.

populate_request(Spec, Req) ->
populate_request(Spec, Req, #{}).

-spec validate_response(
Spec :: response_spec(),
RespBody :: {{packageName}}:object() | [{{packageName}}:object()] | undefined
RespBody :: {{packageName}}:body_schema() | [{{packageName}}:body_schema()] | undefined
) ->
ok | no_return().

Expand All @@ -93,7 +80,12 @@ validate_response(Spec, RespBody) ->
erlang:error({response_validation_failed, Error, RespBody})
end.

-spec encode_response(Resp :: {{packageName}}_logic_handler:response()) ->
-spec encode_response(Response) ->
Response :: {
cowboy:http_status(),
cowboy:http_headers(),
{{packageName}}:body_schema() | [{{packageName}}:body_schema()] | undefined
},
Encoded :: response().

encode_response(Resp = {_, _, undefined}) ->
Expand Down Expand Up @@ -216,7 +208,7 @@ get_value(binding, Name, Req0) ->
{ok, Value, Req}.

-spec decode_body(Body :: binary()) ->
{ok, Decoded :: {{packageName}}:object() | undefined} |
{ok, Decoded :: map() | undefined} |
{error, Message :: {{packageName}}:error_reason()}.
decode_body(<<>>) ->
{ok, undefined};
Expand Down

This file was deleted.

Original file line number Diff line number Diff line change
Expand Up @@ -6,44 +6,46 @@
Method :: binary() => OperationID :: {{packageName}}:operation_id()
}.

-type handler() :: module() | {module(), _Opts}.

-type init_opts() :: {
Operations :: operations(),
LogicHandler :: atom()
LogicHandler :: handler()
}.

-export_type([init_opts/0]).

-spec get_paths(LogicHandler :: atom()) -> [{'_',[{
-spec get_paths(LogicHandlers :: #{atom() => handler()}) -> [{'_',[{
Path :: string(),
Handler :: atom(),
InitOpts :: init_opts()
}]}].

get_paths(LogicHandler) ->
get_paths(LogicHandlers) ->
PreparedPaths = maps:fold(
fun(Path, #{operations := Operations, handler := Handler}, Acc) ->
[{Path, Handler, Operations} | Acc]
fun(Path, #{operations := Operations, handler := Handler, key := Key}, Acc) ->
[{Path, Handler, {Key, Operations}} | Acc]
end,
[],
group_paths()
),
[
{'_',
[{P, H, {O, LogicHandler}} || {P, H, O} <- PreparedPaths]
[{P, H, {O, maps:get(K, LogicHandlers)}} || {P, H, {K, O}} <- PreparedPaths]
}
].

group_paths() ->
maps:fold(
fun(OperationID, #{path := Path, method := Method, handler := Handler}, Acc) ->
fun(OperationID, #{path := Path, method := Method, handler := Handler, key := Key}, Acc) ->
case maps:find(Path, Acc) of
{ok, PathInfo0 = #{operations := Operations0}} ->
Operations = Operations0#{Method => OperationID},
PathInfo = PathInfo0#{operations => Operations},
Acc#{Path => PathInfo};
error ->
Operations = #{Method => OperationID},
PathInfo = #{handler => Handler, operations => Operations},
PathInfo = #{handler => Handler, operations => Operations, key => Key},
Acc#{Path => PathInfo}
end
end,
Expand All @@ -56,6 +58,7 @@ get_operations() ->
'{{operationId}}' => #{
path => "{{basePathWithoutHost}}{{path}}",
method => <<"{{httpMethod}}">>,
handler => '{{classname}}'
handler => '{{classname}}',
key => '{{classVarName}}'
}{{#hasMore}},{{/hasMore}}{{/operation}}{{#hasMore}},{{/hasMore}}{{/operations}}{{/apis}}{{/apiInfo}}
}.
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@

-define(DEFINITIONS, <<"definitions">>).

-spec get() -> {{packageName}}:object().
-spec get() -> map().
get() ->
ct_expand:term(enumerate_discriminator_children(maps:with([?DEFINITIONS], get_raw()))).

Expand Down
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
%% -*- mode: erlang -*-
-module({{packageName}}).
%% Type definitions

Expand All @@ -10,10 +11,16 @@
-export_type([api_key/0]).
-export_type([object/0]).

-type auth_context() :: any().
-type operation_id() :: atom().
-type auth_context() :: any().
-type auth_result() :: false | {true, auth_context()}.
-type api_key() :: binary().
-type object() :: map().

-type body_schema() :: #{binary() => term()}.
-type object() :: #{
binary() => term(),
atom() => term()
}.

-type client_peer() :: #{
ip_address => IP :: inet:ip_address(),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,11 @@
-export([join/1]).
-export([join/2]).

-spec get_handler_and_opts({{package_name}}:handler()) -> {module(), undefined | term()}.
get_handler_and_opts({Handler, Opts}) ->
{Handler, Opts};
get_handler_and_opts(Handler) ->
get_handler_and_opts({Handler, undefined}).

-spec to_binary(iodata() | atom() | number()) -> binary().

Expand Down
Loading