Skip to content
Merged
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
2 changes: 1 addition & 1 deletion bin/erlang-petstore-client.sh
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,6 @@ fi

# if you've executed sbt assembly previously it will use that instead.
export JAVA_OPTS="${JAVA_OPTS} -XX:MaxPermSize=256M -Xmx1024M -DloggerPath=conf/log4j.properties"
ags="$@ generate -t modules/swagger-codegen/src/main/resources/erlang-client -i modules/swagger-codegen/src/test/resources/2_0/petstore.yaml -l erlang-client -o samples/client/petstore/erlang-client"
ags="$@ generate -t modules/swagger-codegen/src/main/resources/erlang-client -DpackageName=petstore -i modules/swagger-codegen/src/test/resources/2_0/petstore.yaml -l erlang-client -o samples/client/petstore/erlang-client"

java $JAVA_OPTS -jar $executable $ags
Original file line number Diff line number Diff line change
Expand Up @@ -157,6 +157,7 @@ public void execute(Template.Fragment fragment, Writer writer) throws IOExceptio

supportingFiles.add(new SupportingFile("rebar.config.mustache","", "rebar.config"));
supportingFiles.add(new SupportingFile("app.src.mustache", "", "src" + File.separator + this.packageName + ".app.src"));
supportingFiles.add(new SupportingFile("utils.mustache", "", "src" + File.separator + this.packageName + "_utils.erl"));
supportingFiles.add(new SupportingFile("README.mustache", "", "README.md"));
}

Expand Down Expand Up @@ -221,23 +222,24 @@ public String toParamName(String name) {

@Override
public String toModelName(String name) {
return this.packageName + "_" + underscore(name.replaceAll("-", "_"));
return this.packageName + "_" + underscore(name.replaceAll("-", "_").replaceAll("\\.", "_"));
}

@Override
public String toApiName(String name) {
return this.packageName + "_" + underscore(name.replaceAll("-", "_"));
return this.packageName + "_" + underscore(name.replaceAll("-", "_").replaceAll("\\.", "_"));
}

@Override
public String toModelFilename(String name) {
return this.packageName + "_" + underscore(name);
return this.packageName + "_" + underscore(name.replaceAll("\\.", "_"));
}

@Override
public String toApiFilename(String name) {
// replace - with _ e.g. created-at => created_at
name = name.replaceAll("-", "_"); // FIXME: a parameter should not be assigned. Also declare the methods parameters as 'final'.
// FIXME: a parameter should not be assigned. Also declare the methods parameters as 'final'.
name = name.replaceAll("-", "_").replaceAll("\\.", "_");

// e.g. PetApi.erl => pet_api.erl
return this.packageName + "_" + underscore(name) + "_api";
Expand All @@ -247,11 +249,11 @@ public String toApiFilename(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 " + underscore(sanitizeName("call_" + operationId)));
LOGGER.warn(operationId + " (reserved word) cannot be used as method name. Renamed to " + underscore(sanitizeName("call_" + operationId)).replaceAll("\\.", "_"));
operationId = "call_" + operationId;
}

return underscore(operationId);
return underscore(operationId.replaceAll("\\.", "_"));
}

@Override
Expand Down Expand Up @@ -379,8 +381,8 @@ public ExtendedCodegenOperation(CodegenOperation o) {
this.produces = o.produces;
this.bodyParam = o.bodyParam;
this.allParams = o.allParams;
this.arityRequired = Integer.toString(lengthRequired(o.allParams));
this.arityOptional = Integer.toString(lengthRequired(o.allParams)+1);
this.arityRequired = Integer.toString(lengthRequired(o.allParams)+1);
this.arityOptional = Integer.toString(lengthRequired(o.allParams)+2);
this.bodyParams = o.bodyParams;
this.pathParams = o.pathParams;
this.queryParams = o.queryParams;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,49 +3,32 @@
-export([{{#operations}}{{#operation}}{{^-first}},
{{/-first}}{{operationId}}/{{arityRequired}}, {{operationId}}/{{arityOptional}}{{/operation}}{{/operations}}]).

-define(BASE_URL, <<"{{{basePath}}}">>).
-define(BASE_URL, "{{{basePathWithoutHost}}}").

{{#operations}}
{{#operation}}
%% @doc {{{summary}}}
{{^notes.isEmpty}}
%% {{{notes}}}
{{/notes.isEmpty}}
-spec {{operationId}}({{#allParams}}{{#required}}{{^-first}}, {{/-first}}{{{dataType}}}{{/required}}{{/allParams}}{{^bodyParams.isEmpty}}{{#bodyParams}}, term(){{/bodyParams}}{{/bodyParams.isEmpty}}) -> {{#returnType}}{ok, list(), {{{returnType}}}} | {error, string()}{{/returnType}}{{^returnType}}ok | {error, integer()}{{/returnType}}.
{{operationId}}({{#allParams}}{{#required}}{{^-first}}, {{/-first}}{{paramName}}{{/required}}{{/allParams}}{{^bodyParams.isEmpty}}{{#bodyParams}}, {{paramName}}{{/bodyParams}}{{/bodyParams.isEmpty}}) ->
{{operationId}}({{#allParams}}{{#required}}{{paramName}}, {{/required}}{{/allParams}}{{^bodyParams.isEmpty}}{{#bodyParams}}{{paramName}}, {{/bodyParams}}{{/bodyParams.isEmpty}}#{}).
-spec {{operationId}}(ctx:ctx(){{#allParams}}{{#required}}, {{{dataType}}}{{/required}}{{/allParams}}) -> {ok, {{#returnType}}{{{returnType}}}{{/returnType}}{{^returnType}}[]{{/returnType}}, {{packageName}}_utils:response_info()} | {ok, hackney:client_ref()} | {error, term(), {{packageName}}_utils:response_info()}.
{{operationId}}(Ctx{{#allParams}}{{#required}}, {{paramName}}{{/required}}{{/allParams}}) ->
{{operationId}}(Ctx{{#allParams}}{{#required}}, {{paramName}}{{/required}}{{/allParams}}, #{}).

-spec {{operationId}}(ctx:ctx(){{#allParams}}{{#required}}, {{{dataType}}}{{/required}}{{/allParams}}, maps:map()) -> {ok, {{#returnType}}{{{returnType}}}{{/returnType}}{{^returnType}}[]{{/returnType}}, {{packageName}}_utils:response_info()} | {ok, hackney:client_ref()} | {error, term(), {{packageName}}_utils:response_info()}.
{{operationId}}(Ctx{{#allParams}}{{#required}}, {{paramName}}{{/required}}{{/allParams}}, Optional) ->
_OptionalParams = maps:get(params, Optional, #{}),
Cfg = maps:get(cfg, Optional, application:get_env(kuberl, config, #{})),

-spec {{operationId}}({{#allParams}}{{#required}}{{{dataType}}}, {{/required}}{{/allParams}}{{^bodyParams.isEmpty}}{{#bodyParams}}term(), {{/bodyParams}}{{/bodyParams.isEmpty}}maps:map()) -> {{#returnType}}{ok, list(), {{{returnType}}}} | {error, string()}{{/returnType}}{{^returnType}}ok | {error, integer()}{{/returnType}}.
{{operationId}}({{#allParams}}{{#required}}{{paramName}}, {{/required}}{{/allParams}}{{^bodyParams.isEmpty}}{{#bodyParams}}{{paramName}}{{/bodyParams}}, {{/bodyParams.isEmpty}}_Optional) ->
Method = {{httpMethod}},
Path = ["{{{replacedPathName}}}"],
QS = {{#queryParams.isEmpty}}[]{{/queryParams.isEmpty}}{{^queryParams.isEmpty}}lists:flatten([{{#queryParams}}{{#required}}{{^-first}}, {{/-first}}{{#qsEncode}}{{this}}{{/qsEncode}}{{/required}}{{/queryParams}}])++[{X, maps:get(X, _Optional)} || X <- [{{#queryParams}}{{^required}}{{^-first}}, {{/-first}}'{{baseName}}'{{/required}}{{/queryParams}}], maps:is_key(X, _Optional)]{{/queryParams.isEmpty}},
Headers = {{#headerParams.isEmpty}}[]{{/headerParams.isEmpty}}{{^headerParams.isEmpty}}[{{#headerParams}}{{#required}}{{^-first}}, {{/-first}}{<<"{{baseName}}">>, {{paramName}}}{{/required}}{{/headerParams}}]++[{X, maps:get(X, _Optional)} || X <- [{{#headerParams}}{{^required}}{{^-first}}, {{/-first}}'{{baseName}}'{{/required}}{{/headerParams}}], maps:is_key(X, _Optional)]{{/headerParams.isEmpty}},
Body1 = {{^formParams.isEmpty}}{form, [{{#formParams}}{{#required}}{{^-first}}, {{/-first}}{<<"{{baseName}}">>, {{paramName}}}{{/required}}{{/formParams}}]++[{X, maps:get(X, _Optional)} || X <- [{{#formParams}}{{^required}}{{^-first}}, {{/-first}}'{{baseName}}'{{/required}}{{/formParams}}], maps:is_key(X, _Optional)]}{{/formParams.isEmpty}}{{#formParams.isEmpty}}{{#bodyParams.isEmpty}}[]{{/bodyParams.isEmpty}}{{^bodyParams.isEmpty}}{{#bodyParams}}{{paramName}}{{/bodyParams}}{{/bodyParams.isEmpty}}{{/formParams.isEmpty}},
Opts = [],
Url = hackney_url:make_url(?BASE_URL, Path, QS),

case hackney:request(Method, Url, Headers, Body1, Opts) of
{{#returnType}}
{{#responses}}
{{#isDefault}}
{ok, {{code}}, RespHeaders, ClientRef} ->
{ok, ResponseBody} = hackney:body(ClientRef),
{ok, RespHeaders, jsx:decode(ResponseBody, [return_maps])}{{#hasMore}}; {{/hasMore}}
{{/isDefault}}
{{^isDefault}}
{ok, {{code}}, _RespHeaders, _ClientRef} ->
{error, "{{message}}"}{{#hasMore}}; {{/hasMore}}
{{/isDefault}}
{{/responses}}
{{/returnType}}
{{^returnType}}
{ok, 200, _RespHeaders, _ClientRef} ->
ok;
{ok, Status, _RespHeaders, _ClientRef} ->
{error, Status}
{{/returnType}}
end.
QS = {{#queryParams.isEmpty}}[]{{/queryParams.isEmpty}}{{^queryParams.isEmpty}}lists:flatten([{{#queryParams}}{{#required}}{{^-first}}, {{/-first}}{{#qsEncode}}{{this}}{{/qsEncode}}{{/required}}{{/queryParams}}])++{{packageName}}_utils:optional_params([{{#queryParams}}{{^required}}{{^-first}}, {{/-first}}'{{baseName}}'{{/required}}{{/queryParams}}], _OptionalParams){{/queryParams.isEmpty}},
Headers = {{#headerParams.isEmpty}}[]{{/headerParams.isEmpty}}{{^headerParams.isEmpty}}[{{#headerParams}}{{#required}}{{^-first}}, {{/-first}}{<<"{{baseName}}">>, {{paramName}}}{{/required}}{{/headerParams}}]++{{packageName}}_utils:optional_params([{{#headerParams}}{{^required}}{{^-first}}, {{/-first}}'{{baseName}}'{{/required}}{{/headerParams}}], _OptionalParams){{/headerParams.isEmpty}},
Body1 = {{^formParams.isEmpty}}{form, [{{#formParams}}{{#required}}{{^-first}}, {{/-first}}{<<"{{baseName}}">>, {{paramName}}}{{/required}}{{/formParams}}]++{{packageName}}_utils:optional_params([{{#formParams}}{{^required}}{{^-first}}, {{/-first}}'{{baseName}}'{{/required}}{{/formParams}}], _OptionalParams)}{{/formParams.isEmpty}}{{#formParams.isEmpty}}{{#bodyParams.isEmpty}}[]{{/bodyParams.isEmpty}}{{^bodyParams.isEmpty}}{{#bodyParams}}{{paramName}}{{/bodyParams}}{{/bodyParams.isEmpty}}{{/formParams.isEmpty}},
ContentTypeHeader = {{packageName}}_utils:select_header_content_type([{{#consumes}}{{^-first}}, {{/-first}}<<"{{mediaType}}">>{{/consumes}}]),
Opts = maps:get(hackney_opts, Optional, []),

{{packageName}}_utils:request(Ctx, Method, [?BASE_URL, Path], QS, ContentTypeHeader++Headers, Body1, Opts, Cfg).

{{/operation}}

Expand Down
Original file line number Diff line number Diff line change
@@ -1,14 +1,15 @@
{application, {{packageName}},
[{description, {{#appDescription}}"{{appDescription}}"{{/appDescription}}{{^appDescription}}"Swagger client library"{{/appDescription}}},
{vsn, "{{apiVersion}}"},
{vsn, "{{#apiVersion}}{{apiVersion}}{{/apiVersion}}{{^apiVersion}}0.1.0{{/apiVersion}}"},
{registered, []},
{applications,
[kernel,
stdlib,
ssl,
hackney
hackney,
ctx
]},
{env, []},
{env, [{host, "{{#host}}{{{host}}}{{/host}}{{^host}}localhost{{/host}}"}]},
{modules, []},

{maintainers, []},
Expand Down
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
{erl_opts, [debug_info, warnings_as_errors, warn_untyped_record]}.

{deps, [jsx, hackney]}.
{deps, [ctx, jsx, hackney]}.

{shell, [{apps, [{{packageName}}]}]}.
Original file line number Diff line number Diff line change
@@ -0,0 +1,94 @@
-module({{packageName}}_utils).

-export([request/8,
select_header_content_type/1,
optional_params/2]).

-type response_info() :: #{status := integer(),
headers := list()}.
-export_type([response_info/0]).

request(_Ctx, Method, Path, QS, Headers, Body, Opts, Cfg) ->
{Headers1, QS1} = update_params_with_auth(Cfg, Headers, QS),
Host = maps:get(host, Cfg, "localhost:8001"),
Url = hackney_url:make_url(Host, Path, QS1),

ConfigHackneyOpts = maps:get(hackney_opts, Cfg, []),
Body1 = case lists:keyfind(<<"Content-Type">>, 1, Headers1) of
{_, <<"application/json", _/binary>>} ->
jsx:encode(Body);
_ ->
Body
end,

case hackney:request(Method, Url, Headers1, Body1, Opts++ConfigHackneyOpts) of
{ok, ClientRef} ->
%% return value if Opts includes `async`
{ok, ClientRef};
{ok, Status, RespHeaders, ClientRef} when Status >= 200,
Status =< 299 ->
{ok, ResponseBody} = hackney:body(ClientRef),
Resp = decode_response(RespHeaders, ResponseBody),
{ok, Resp, #{status => Status,
headers => RespHeaders}};
{ok, Status, RespHeaders, ClientRef} when Status >= 300 ->
{ok, ResponseBody} = hackney:body(ClientRef),
Resp = decode_response(RespHeaders, ResponseBody),
{error, Resp, #{status => Status,
headers => RespHeaders}}
end.

decode_response(Headers, Body) ->
case lists:keyfind(<<"Content-Type">>, 1, Headers) of
{_, <<"application/json", _/binary>>} ->
jsx:decode(Body, [return_maps, {labels, atom}]);
%% TODO: yml, protobuf, user defined function
_ ->
Body
end.

optional_params([], _Params) -> [];
optional_params(Keys, Params) ->
[{Key, maps:get(Key, Params)} || Key <- Keys, maps:is_key(Key, Params)].

select_header_content_type([]) ->
[];
select_header_content_type(ContentTypes) ->
case lists:member(<<"application/json">>, ContentTypes) orelse lists:member(<<"*/*">>, ContentTypes) of
true ->
[{<<"Content-Type">>, <<"application/json">>}];
false ->
[{<<"Content-Type">>, hd(ContentTypes)}]
end.

auth_with_prefix(Cfg, Key, Token) ->
Prefixes = maps:get(api_key_prefix, Cfg, #{}),
case maps:get(Key, Prefixes, undefined) of
undefined ->
Token;
Prefix ->
<<Prefix/binary, " ", Token/binary>>
end.

update_params_with_auth(Cfg, Headers, QS) ->
AuthSettings = maps:get(auth, Cfg, #{}),
Auths = #{ {{#authMethods}}'{{name}}' =>
#{type => '{{type}}',
key => <<"{{keyParamName}}">>,
in => {{#isKeyInHeader}}header{{/isKeyInHeader}}{{#isKeyInQuery}}query{{/isKeyInQuery}}}{{#hasMore}}, {{/hasMore}}{{/authMethods}}},

maps:fold(fun(AuthName, #{type := _Type,
in := In,
key := Key}, {HeadersAcc, QSAcc}) ->
case maps:get(AuthName, AuthSettings, undefined) of
undefined ->
{HeadersAcc, QSAcc};
Value ->
case In of
header ->
{[{Key, auth_with_prefix(Cfg, Key, Value)} | HeadersAcc], QSAcc};
query ->
{HeadersAcc, [{Key, auth_with_prefix(Cfg, Key, Value)} | QSAcc]}
end
end
end, {Headers, QS}, Auths).
Original file line number Diff line number Diff line change
@@ -1 +1 @@
2.3.0-SNAPSHOT
2.3.0
4 changes: 3 additions & 1 deletion samples/client/petstore/erlang-client/rebar.config
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
{erl_opts, [debug_info, warnings_as_errors, warn_untyped_record]}.

{deps, [jsx, hackney]}.
{deps, [ctx, jsx, hackney]}.

{shell, [{apps, [petstore]}]}.
Original file line number Diff line number Diff line change
@@ -1,14 +1,15 @@
{application, swagger,
{application, petstore,
[{description, "This is a sample server Petstore server. You can find out more about Swagger at [http://swagger.io](http://swagger.io) or on [irc.freenode.net, #swagger](http://swagger.io/irc/). For this sample, you can use the api key &#x60;special-key&#x60; to test the authorization filters."},
{vsn, ""},
{vsn, "0.1.0"},
{registered, []},
{applications,
[kernel,
stdlib,
ssl,
hackney
hackney,
ctx
]},
{env, []},
{env, [{host, "petstore.swagger.io"}]},
{modules, []},

{maintainers, []},
Expand Down
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
-module(swagger_api_response).
-module(petstore_api_response).

-export([encode/1]).

-export_type([swagger_api_response/0]).
-export_type([petstore_api_response/0]).

-type swagger_api_response() ::
-type petstore_api_response() ::
#{ 'code' => integer(),
'type' => binary(),
'message' => binary()
Expand Down
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
-module(swagger_category).
-module(petstore_category).

-export([encode/1]).

-export_type([swagger_category/0]).
-export_type([petstore_category/0]).

-type swagger_category() ::
-type petstore_category() ::
#{ 'id' => integer(),
'name' => binary()
}.
Expand Down
Original file line number Diff line number Diff line change
@@ -1,14 +1,14 @@
-module(swagger_order).
-module(petstore_order).

-export([encode/1]).

-export_type([swagger_order/0]).
-export_type([petstore_order/0]).

-type swagger_order() ::
-type petstore_order() ::
#{ 'id' => integer(),
'petId' => integer(),
'quantity' => integer(),
'shipDate' => swagger_date_time:swagger_date_time(),
'shipDate' => petstore_date_time:petstore_date_time(),
'status' => binary(),
'complete' => boolean()
}.
Expand Down
Original file line number Diff line number Diff line change
@@ -1,12 +1,12 @@
-module(swagger_pet).
-module(petstore_pet).

-export([encode/1]).

-export_type([swagger_pet/0]).
-export_type([petstore_pet/0]).

-type swagger_pet() ::
-type petstore_pet() ::
#{ 'id' => integer(),
'category' => swagger_category:swagger_category(),
'category' => petstore_category:petstore_category(),
'name' := binary(),
'photoUrls' := list(),
'tags' => list(),
Expand Down
Loading