From a13e0e28c0de0db66a84f9892f24397f8fbe482d Mon Sep 17 00:00:00 2001 From: Tristan Sloughter Date: Thu, 21 Dec 2017 20:05:17 -0800 Subject: [PATCH 1/5] [erlang-client] fix body param from being included path and base path to remove host --- .../languages/ErlangClientCodegen.java | 30 ++++++++++--- .../main/resources/erlang-client/api.mustache | 12 +++--- .../erlang-client/src/swagger_pet_api.erl | 30 ++++++------- .../erlang-client/src/swagger_store_api.erl | 20 ++++----- .../erlang-client/src/swagger_user_api.erl | 42 +++++++++---------- 5 files changed, 76 insertions(+), 58 deletions(-) diff --git a/modules/swagger-codegen/src/main/java/io/swagger/codegen/languages/ErlangClientCodegen.java b/modules/swagger-codegen/src/main/java/io/swagger/codegen/languages/ErlangClientCodegen.java index d41daa8576c..9a2e658667a 100644 --- a/modules/swagger-codegen/src/main/java/io/swagger/codegen/languages/ErlangClientCodegen.java +++ b/modules/swagger-codegen/src/main/java/io/swagger/codegen/languages/ErlangClientCodegen.java @@ -117,6 +117,24 @@ public String getSwaggerType(Property p) { return type; } + public static String underscore2(String word) { + String firstPattern = "([A-Z]+)([A-Z][a-z])"; + String secondPattern = "([a-z\\d])([A-Z])"; + String replacementPattern = "$1_$2"; + // Replace package separator with slash. + word = word.replaceAll("\\.", "_"); // FIXME: a parameter should not be assigned. Also declare the methods parameters as 'final'. + // Replace $ with two underscores for inner classes. + word = word.replaceAll("\\$", "__"); + // Replace capital letter with _ plus lowercase letter. + word = word.replaceAll(firstPattern, replacementPattern); + word = word.replaceAll(secondPattern, replacementPattern); + word = word.replace('-', '_'); + // replace space with underscore + word = word.replace(' ', '_'); + word = word.toLowerCase(); + return word; + } + @Override public void processOpts() { super.processOpts(); @@ -221,17 +239,17 @@ public String toParamName(String name) { @Override public String toModelName(String name) { - return this.packageName + "_" + underscore(name.replaceAll("-", "_")); + return this.packageName + "_" + underscore2(name.replaceAll("-", "_")); } @Override public String toApiName(String name) { - return this.packageName + "_" + underscore(name.replaceAll("-", "_")); + return this.packageName + "_" + underscore2(name.replaceAll("-", "_")); } @Override public String toModelFilename(String name) { - return this.packageName + "_" + underscore(name); + return this.packageName + "_" + underscore2(name); } @Override @@ -240,18 +258,18 @@ public String toApiFilename(String name) { name = name.replaceAll("-", "_"); // FIXME: a parameter should not be assigned. Also declare the methods parameters as 'final'. // e.g. PetApi.erl => pet_api.erl - return this.packageName + "_" + underscore(name) + "_api"; + return this.packageName + "_" + underscore2(name) + "_api"; } @Override 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 " + underscore2(sanitizeName("call_" + operationId))); operationId = "call_" + operationId; } - return underscore(operationId); + return underscore2(operationId); } @Override diff --git a/modules/swagger-codegen/src/main/resources/erlang-client/api.mustache b/modules/swagger-codegen/src/main/resources/erlang-client/api.mustache index 21f040192f0..4fe102f1dcd 100644 --- a/modules/swagger-codegen/src/main/resources/erlang-client/api.mustache +++ b/modules/swagger-codegen/src/main/resources/erlang-client/api.mustache @@ -3,7 +3,7 @@ -export([{{#operations}}{{#operation}}{{^-first}}, {{/-first}}{{operationId}}/{{arityRequired}}, {{operationId}}/{{arityOptional}}{{/operation}}{{/operations}}]). --define(BASE_URL, <<"{{{basePath}}}">>). +-define(BASE_URL, <<"{{{basePathWithoutHost}}}">>). {{#operations}} {{#operation}} @@ -11,12 +11,12 @@ {{^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}}({{#allParams}}{{#required}}{{^-first}}, {{/-first}}{{{dataType}}}{{/required}}{{/allParams}}) -> {{#returnType}}{ok, list(), {{{returnType}}}} | {error, string()}{{/returnType}}{{^returnType}}ok | {error, integer()}{{/returnType}}. +{{operationId}}({{#allParams}}{{#required}}{{^-first}}, {{/-first}}{{paramName}}{{/required}}{{/allParams}}) -> + {{operationId}}({{#allParams}}{{#required}}{{paramName}}, {{/required}}{{/allParams}}#{}). --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) -> +-spec {{operationId}}({{#allParams}}{{#required}}{{{dataType}}}, {{/required}}{{/allParams}}maps:map()) -> {{#returnType}}{ok, list(), {{{returnType}}}} | {error, string()}{{/returnType}}{{^returnType}}ok | {error, integer()}{{/returnType}}. +{{operationId}}({{#allParams}}{{#required}}{{paramName}}, {{/required}}{{/allParams}}_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}}, diff --git a/samples/client/petstore/erlang-client/src/swagger_pet_api.erl b/samples/client/petstore/erlang-client/src/swagger_pet_api.erl index 997fd7820b9..7bcf82f2583 100644 --- a/samples/client/petstore/erlang-client/src/swagger_pet_api.erl +++ b/samples/client/petstore/erlang-client/src/swagger_pet_api.erl @@ -9,15 +9,15 @@ update_pet_with_form/1, update_pet_with_form/2, upload_file/1, upload_file/2]). --define(BASE_URL, <<"http://petstore.swagger.io/v2">>). +-define(BASE_URL, <<"/v2">>). %% @doc Add a new pet to the store --spec add_pet(swagger_pet:swagger_pet(), term()) -> ok | {error, integer()}. +-spec add_pet(swagger_pet:swagger_pet()) -> ok | {error, integer()}. add_pet(Body) -> - add_pet(Body, Body, #{}). + add_pet(Body, #{}). --spec add_pet(swagger_pet:swagger_pet(), term(), maps:map()) -> ok | {error, integer()}. -add_pet(Body, Body, _Optional) -> +-spec add_pet(swagger_pet:swagger_pet(), maps:map()) -> ok | {error, integer()}. +add_pet(Body, _Optional) -> Method = post, Path = ["/pet"], QS = [], @@ -36,7 +36,7 @@ add_pet(Body, Body, _Optional) -> %% @doc Deletes a pet -spec delete_pet(integer()) -> ok | {error, integer()}. delete_pet(PetId) -> - delete_pet(PetId, , #{}). + delete_pet(PetId, #{}). -spec delete_pet(integer(), maps:map()) -> ok | {error, integer()}. delete_pet(PetId, _Optional) -> @@ -59,7 +59,7 @@ delete_pet(PetId, _Optional) -> %% Multiple status values can be provided with comma separated strings -spec find_pets_by_status(list()) -> {ok, list(), [swagger_pet:swagger_pet()]} | {error, string()}. find_pets_by_status(Status) -> - find_pets_by_status(Status, , #{}). + find_pets_by_status(Status, #{}). -spec find_pets_by_status(list(), maps:map()) -> {ok, list(), [swagger_pet:swagger_pet()]} | {error, string()}. find_pets_by_status(Status, _Optional) -> @@ -83,7 +83,7 @@ find_pets_by_status(Status, _Optional) -> %% Multiple tags can be provided with comma separated strings. Use tag1, tag2, tag3 for testing. -spec find_pets_by_tags(list()) -> {ok, list(), [swagger_pet:swagger_pet()]} | {error, string()}. find_pets_by_tags(Tags) -> - find_pets_by_tags(Tags, , #{}). + find_pets_by_tags(Tags, #{}). -spec find_pets_by_tags(list(), maps:map()) -> {ok, list(), [swagger_pet:swagger_pet()]} | {error, string()}. find_pets_by_tags(Tags, _Optional) -> @@ -107,7 +107,7 @@ find_pets_by_tags(Tags, _Optional) -> %% Returns a single pet -spec get_pet_by_id(integer()) -> {ok, list(), swagger_pet:swagger_pet()} | {error, string()}. get_pet_by_id(PetId) -> - get_pet_by_id(PetId, , #{}). + get_pet_by_id(PetId, #{}). -spec get_pet_by_id(integer(), maps:map()) -> {ok, list(), swagger_pet:swagger_pet()} | {error, string()}. get_pet_by_id(PetId, _Optional) -> @@ -130,12 +130,12 @@ get_pet_by_id(PetId, _Optional) -> end. %% @doc Update an existing pet --spec update_pet(swagger_pet:swagger_pet(), term()) -> ok | {error, integer()}. +-spec update_pet(swagger_pet:swagger_pet()) -> ok | {error, integer()}. update_pet(Body) -> - update_pet(Body, Body, #{}). + update_pet(Body, #{}). --spec update_pet(swagger_pet:swagger_pet(), term(), maps:map()) -> ok | {error, integer()}. -update_pet(Body, Body, _Optional) -> +-spec update_pet(swagger_pet:swagger_pet(), maps:map()) -> ok | {error, integer()}. +update_pet(Body, _Optional) -> Method = put, Path = ["/pet"], QS = [], @@ -154,7 +154,7 @@ update_pet(Body, Body, _Optional) -> %% @doc Updates a pet in the store with form data -spec update_pet_with_form(integer()) -> ok | {error, integer()}. update_pet_with_form(PetId) -> - update_pet_with_form(PetId, , #{}). + update_pet_with_form(PetId, #{}). -spec update_pet_with_form(integer(), maps:map()) -> ok | {error, integer()}. update_pet_with_form(PetId, _Optional) -> @@ -176,7 +176,7 @@ update_pet_with_form(PetId, _Optional) -> %% @doc uploads an image -spec upload_file(integer()) -> {ok, list(), swagger_api_response:swagger_api_response()} | {error, string()}. upload_file(PetId) -> - upload_file(PetId, , #{}). + upload_file(PetId, #{}). -spec upload_file(integer(), maps:map()) -> {ok, list(), swagger_api_response:swagger_api_response()} | {error, string()}. upload_file(PetId, _Optional) -> diff --git a/samples/client/petstore/erlang-client/src/swagger_store_api.erl b/samples/client/petstore/erlang-client/src/swagger_store_api.erl index acb72dd415d..2c04f7049db 100644 --- a/samples/client/petstore/erlang-client/src/swagger_store_api.erl +++ b/samples/client/petstore/erlang-client/src/swagger_store_api.erl @@ -5,13 +5,13 @@ get_order_by_id/1, get_order_by_id/2, place_order/1, place_order/2]). --define(BASE_URL, <<"http://petstore.swagger.io/v2">>). +-define(BASE_URL, <<"/v2">>). %% @doc Delete purchase order by ID -%% For valid response try integer IDs with value < 1000. Anything above 1000 or nonintegers will generate API errors +%% For valid response try integer IDs with value < 1000. Anything above 1000 or nonintegers will generate API errors -spec delete_order(binary()) -> ok | {error, integer()}. delete_order(OrderId) -> - delete_order(OrderId, , #{}). + delete_order(OrderId, #{}). -spec delete_order(binary(), maps:map()) -> ok | {error, integer()}. delete_order(OrderId, _Optional) -> @@ -34,7 +34,7 @@ delete_order(OrderId, _Optional) -> %% Returns a map of status codes to quantities -spec get_inventory() -> {ok, list(), maps:map()} | {error, string()}. get_inventory() -> - get_inventory(, #{}). + get_inventory(#{}). -spec get_inventory(maps:map()) -> {ok, list(), maps:map()} | {error, string()}. get_inventory(_Optional) -> @@ -53,10 +53,10 @@ get_inventory(_Optional) -> end. %% @doc Find purchase order by ID -%% For valid response try integer IDs with value <= 5 or > 10. Other values will generated exceptions +%% For valid response try integer IDs with value <= 5 or > 10. Other values will generated exceptions -spec get_order_by_id(integer()) -> {ok, list(), swagger_order:swagger_order()} | {error, string()}. get_order_by_id(OrderId) -> - get_order_by_id(OrderId, , #{}). + get_order_by_id(OrderId, #{}). -spec get_order_by_id(integer(), maps:map()) -> {ok, list(), swagger_order:swagger_order()} | {error, string()}. get_order_by_id(OrderId, _Optional) -> @@ -79,12 +79,12 @@ get_order_by_id(OrderId, _Optional) -> end. %% @doc Place an order for a pet --spec place_order(swagger_order:swagger_order(), term()) -> {ok, list(), swagger_order:swagger_order()} | {error, string()}. +-spec place_order(swagger_order:swagger_order()) -> {ok, list(), swagger_order:swagger_order()} | {error, string()}. place_order(Body) -> - place_order(Body, Body, #{}). + place_order(Body, #{}). --spec place_order(swagger_order:swagger_order(), term(), maps:map()) -> {ok, list(), swagger_order:swagger_order()} | {error, string()}. -place_order(Body, Body, _Optional) -> +-spec place_order(swagger_order:swagger_order(), maps:map()) -> {ok, list(), swagger_order:swagger_order()} | {error, string()}. +place_order(Body, _Optional) -> Method = post, Path = ["/store/order"], QS = [], diff --git a/samples/client/petstore/erlang-client/src/swagger_user_api.erl b/samples/client/petstore/erlang-client/src/swagger_user_api.erl index 837546f27d3..215bf9df11d 100644 --- a/samples/client/petstore/erlang-client/src/swagger_user_api.erl +++ b/samples/client/petstore/erlang-client/src/swagger_user_api.erl @@ -9,16 +9,16 @@ logout_user/0, logout_user/1, update_user/2, update_user/3]). --define(BASE_URL, <<"http://petstore.swagger.io/v2">>). +-define(BASE_URL, <<"/v2">>). %% @doc Create user %% This can only be done by the logged in user. --spec create_user(swagger_user:swagger_user(), term()) -> ok | {error, integer()}. +-spec create_user(swagger_user:swagger_user()) -> ok | {error, integer()}. create_user(Body) -> - create_user(Body, Body, #{}). + create_user(Body, #{}). --spec create_user(swagger_user:swagger_user(), term(), maps:map()) -> ok | {error, integer()}. -create_user(Body, Body, _Optional) -> +-spec create_user(swagger_user:swagger_user(), maps:map()) -> ok | {error, integer()}. +create_user(Body, _Optional) -> Method = post, Path = ["/user"], QS = [], @@ -35,12 +35,12 @@ create_user(Body, Body, _Optional) -> end. %% @doc Creates list of users with given input array --spec create_users_with_array_input(list(), term()) -> ok | {error, integer()}. +-spec create_users_with_array_input(list()) -> ok | {error, integer()}. create_users_with_array_input(Body) -> - create_users_with_array_input(Body, Body, #{}). + create_users_with_array_input(Body, #{}). --spec create_users_with_array_input(list(), term(), maps:map()) -> ok | {error, integer()}. -create_users_with_array_input(Body, Body, _Optional) -> +-spec create_users_with_array_input(list(), maps:map()) -> ok | {error, integer()}. +create_users_with_array_input(Body, _Optional) -> Method = post, Path = ["/user/createWithArray"], QS = [], @@ -57,12 +57,12 @@ create_users_with_array_input(Body, Body, _Optional) -> end. %% @doc Creates list of users with given input array --spec create_users_with_list_input(list(), term()) -> ok | {error, integer()}. +-spec create_users_with_list_input(list()) -> ok | {error, integer()}. create_users_with_list_input(Body) -> - create_users_with_list_input(Body, Body, #{}). + create_users_with_list_input(Body, #{}). --spec create_users_with_list_input(list(), term(), maps:map()) -> ok | {error, integer()}. -create_users_with_list_input(Body, Body, _Optional) -> +-spec create_users_with_list_input(list(), maps:map()) -> ok | {error, integer()}. +create_users_with_list_input(Body, _Optional) -> Method = post, Path = ["/user/createWithList"], QS = [], @@ -82,7 +82,7 @@ create_users_with_list_input(Body, Body, _Optional) -> %% This can only be done by the logged in user. -spec delete_user(binary()) -> ok | {error, integer()}. delete_user(Username) -> - delete_user(Username, , #{}). + delete_user(Username, #{}). -spec delete_user(binary(), maps:map()) -> ok | {error, integer()}. delete_user(Username, _Optional) -> @@ -104,7 +104,7 @@ delete_user(Username, _Optional) -> %% @doc Get user by user name -spec get_user_by_name(binary()) -> {ok, list(), swagger_user:swagger_user()} | {error, string()}. get_user_by_name(Username) -> - get_user_by_name(Username, , #{}). + get_user_by_name(Username, #{}). -spec get_user_by_name(binary(), maps:map()) -> {ok, list(), swagger_user:swagger_user()} | {error, string()}. get_user_by_name(Username, _Optional) -> @@ -129,7 +129,7 @@ get_user_by_name(Username, _Optional) -> %% @doc Logs user into the system -spec login_user(binary(), binary()) -> {ok, list(), binary()} | {error, string()}. login_user(Username, Password) -> - login_user(Username, Password, , #{}). + login_user(Username, Password, #{}). -spec login_user(binary(), binary(), maps:map()) -> {ok, list(), binary()} | {error, string()}. login_user(Username, Password, _Optional) -> @@ -152,7 +152,7 @@ login_user(Username, Password, _Optional) -> %% @doc Logs out current logged in user session -spec logout_user() -> ok | {error, integer()}. logout_user() -> - logout_user(, #{}). + logout_user(#{}). -spec logout_user(maps:map()) -> ok | {error, integer()}. logout_user(_Optional) -> @@ -173,12 +173,12 @@ logout_user(_Optional) -> %% @doc Updated user %% This can only be done by the logged in user. --spec update_user(binary(), swagger_user:swagger_user(), term()) -> ok | {error, integer()}. +-spec update_user(binary(), swagger_user:swagger_user()) -> ok | {error, integer()}. update_user(Username, Body) -> - update_user(Username, Body, Body, #{}). + update_user(Username, Body, #{}). --spec update_user(binary(), swagger_user:swagger_user(), term(), maps:map()) -> ok | {error, integer()}. -update_user(Username, Body, Body, _Optional) -> +-spec update_user(binary(), swagger_user:swagger_user(), maps:map()) -> ok | {error, integer()}. +update_user(Username, Body, _Optional) -> Method = put, Path = ["/user/", Username, ""], QS = [], From f29a14bfb19cd5938a3421dbdc402abc2417309d Mon Sep 17 00:00:00 2001 From: Tristan Sloughter Date: Tue, 26 Dec 2017 10:03:57 -0800 Subject: [PATCH 2/5] [erlang-client] move request logic out of api functions to utils module --- bin/erlang-petstore-client.sh | 2 +- .../languages/ErlangClientCodegen.java | 5 +- .../main/resources/erlang-client/api.mustache | 33 +-- .../resources/erlang-client/app.src.mustache | 7 +- .../erlang-client/rebar.config.mustache | 4 +- .../petstore/erlang-client/rebar.config | 4 +- .../src/{swagger.app.src => petstore.app.src} | 9 +- ...response.erl => petstore_api_response.erl} | 6 +- ...ger_category.erl => petstore_category.erl} | 6 +- .../{swagger_order.erl => petstore_order.erl} | 8 +- .../src/{swagger_pet.erl => petstore_pet.erl} | 8 +- .../erlang-client/src/petstore_pet_api.erl | 145 +++++++++++++ .../erlang-client/src/petstore_store_api.erl | 77 +++++++ .../src/{swagger_tag.erl => petstore_tag.erl} | 6 +- .../{swagger_user.erl => petstore_user.erl} | 6 +- .../erlang-client/src/petstore_user_api.erl | 145 +++++++++++++ .../erlang-client/src/petstore_utils.erl | 36 ++++ .../erlang-client/src/swagger_pet_api.erl | 197 ------------------ .../erlang-client/src/swagger_store_api.erl | 104 --------- .../erlang-client/src/swagger_user_api.erl | 197 ------------------ 20 files changed, 448 insertions(+), 557 deletions(-) rename samples/client/petstore/erlang-client/src/{swagger.app.src => petstore.app.src} (81%) rename samples/client/petstore/erlang-client/src/{swagger_api_response.erl => petstore_api_response.erl} (73%) rename samples/client/petstore/erlang-client/src/{swagger_category.erl => petstore_category.erl} (67%) rename samples/client/petstore/erlang-client/src/{swagger_order.erl => petstore_order.erl} (78%) rename samples/client/petstore/erlang-client/src/{swagger_pet.erl => petstore_pet.erl} (78%) create mode 100644 samples/client/petstore/erlang-client/src/petstore_pet_api.erl create mode 100644 samples/client/petstore/erlang-client/src/petstore_store_api.erl rename samples/client/petstore/erlang-client/src/{swagger_tag.erl => petstore_tag.erl} (71%) rename samples/client/petstore/erlang-client/src/{swagger_user.erl => petstore_user.erl} (90%) create mode 100644 samples/client/petstore/erlang-client/src/petstore_user_api.erl create mode 100644 samples/client/petstore/erlang-client/src/petstore_utils.erl delete mode 100644 samples/client/petstore/erlang-client/src/swagger_pet_api.erl delete mode 100644 samples/client/petstore/erlang-client/src/swagger_store_api.erl delete mode 100644 samples/client/petstore/erlang-client/src/swagger_user_api.erl diff --git a/bin/erlang-petstore-client.sh b/bin/erlang-petstore-client.sh index 686ecd25629..a0f1a7ff633 100755 --- a/bin/erlang-petstore-client.sh +++ b/bin/erlang-petstore-client.sh @@ -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 diff --git a/modules/swagger-codegen/src/main/java/io/swagger/codegen/languages/ErlangClientCodegen.java b/modules/swagger-codegen/src/main/java/io/swagger/codegen/languages/ErlangClientCodegen.java index 9a2e658667a..a7f5e5d0ec6 100644 --- a/modules/swagger-codegen/src/main/java/io/swagger/codegen/languages/ErlangClientCodegen.java +++ b/modules/swagger-codegen/src/main/java/io/swagger/codegen/languages/ErlangClientCodegen.java @@ -175,6 +175,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")); } @@ -397,8 +398,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; diff --git a/modules/swagger-codegen/src/main/resources/erlang-client/api.mustache b/modules/swagger-codegen/src/main/resources/erlang-client/api.mustache index 4fe102f1dcd..4e2e26d0c10 100644 --- a/modules/swagger-codegen/src/main/resources/erlang-client/api.mustache +++ b/modules/swagger-codegen/src/main/resources/erlang-client/api.mustache @@ -11,41 +11,20 @@ {{^notes.isEmpty}} %% {{{notes}}} {{/notes.isEmpty}} --spec {{operationId}}({{#allParams}}{{#required}}{{^-first}}, {{/-first}}{{{dataType}}}{{/required}}{{/allParams}}) -> {{#returnType}}{ok, list(), {{{returnType}}}} | {error, string()}{{/returnType}}{{^returnType}}ok | {error, integer()}{{/returnType}}. -{{operationId}}({{#allParams}}{{#required}}{{^-first}}, {{/-first}}{{paramName}}{{/required}}{{/allParams}}) -> - {{operationId}}({{#allParams}}{{#required}}{{paramName}}, {{/required}}{{/allParams}}#{}). +-spec {{operationId}}(ctx:ctx(){{#allParams}}{{#required}}, {{{dataType}}}{{/required}}{{/allParams}}) -> {{#returnType}}{ok, list(), {{{returnType}}}} | {error, string()}{{/returnType}}{{^returnType}}ok | {error, integer()}{{/returnType}}. +{{operationId}}(Ctx{{#allParams}}{{#required}}, {{paramName}}{{/required}}{{/allParams}}) -> + {{operationId}}(Ctx{{#allParams}}{{#required}}, {{paramName}}{{/required}}{{/allParams}}, #{}). --spec {{operationId}}({{#allParams}}{{#required}}{{{dataType}}}, {{/required}}{{/allParams}}maps:map()) -> {{#returnType}}{ok, list(), {{{returnType}}}} | {error, string()}{{/returnType}}{{^returnType}}ok | {error, integer()}{{/returnType}}. -{{operationId}}({{#allParams}}{{#required}}{{paramName}}, {{/required}}{{/allParams}}_Optional) -> +-spec {{operationId}}(ctx:ctx(){{#allParams}}{{#required}}, {{{dataType}}}{{/required}}{{/allParams}}, maps:map()) -> {{#returnType}}{ok, list(), {{{returnType}}}} | {error, string()}{{/returnType}}{{^returnType}}ok | {error, integer()}{{/returnType}}. +{{operationId}}(Ctx{{#allParams}}{{#required}}, {{paramName}}{{/required}}{{/allParams}}, _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. + {{packageName}}_utils:request(Ctx, Method, [?BASE_URL, Path], QS, Headers, Body1, Opts). {{/operation}} diff --git a/modules/swagger-codegen/src/main/resources/erlang-client/app.src.mustache b/modules/swagger-codegen/src/main/resources/erlang-client/app.src.mustache index 8cf0543467a..00adeeb4757 100644 --- a/modules/swagger-codegen/src/main/resources/erlang-client/app.src.mustache +++ b/modules/swagger-codegen/src/main/resources/erlang-client/app.src.mustache @@ -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, []}, diff --git a/modules/swagger-codegen/src/main/resources/erlang-client/rebar.config.mustache b/modules/swagger-codegen/src/main/resources/erlang-client/rebar.config.mustache index abe84a1a9f3..d98643ee266 100644 --- a/modules/swagger-codegen/src/main/resources/erlang-client/rebar.config.mustache +++ b/modules/swagger-codegen/src/main/resources/erlang-client/rebar.config.mustache @@ -1,3 +1,5 @@ {erl_opts, [debug_info, warnings_as_errors, warn_untyped_record]}. -{deps, [jsx, hackney]}. +{deps, [ctx, jsx, hackney]}. + +{shell, [{apps, [{{packageName}}]}]}. \ No newline at end of file diff --git a/samples/client/petstore/erlang-client/rebar.config b/samples/client/petstore/erlang-client/rebar.config index abe84a1a9f3..8633aa236bd 100644 --- a/samples/client/petstore/erlang-client/rebar.config +++ b/samples/client/petstore/erlang-client/rebar.config @@ -1,3 +1,5 @@ {erl_opts, [debug_info, warnings_as_errors, warn_untyped_record]}. -{deps, [jsx, hackney]}. +{deps, [ctx, jsx, hackney]}. + +{shell, [{apps, [petstore]}]}. \ No newline at end of file diff --git a/samples/client/petstore/erlang-client/src/swagger.app.src b/samples/client/petstore/erlang-client/src/petstore.app.src similarity index 81% rename from samples/client/petstore/erlang-client/src/swagger.app.src rename to samples/client/petstore/erlang-client/src/petstore.app.src index 7f4d814ca3e..824eb75e350 100644 --- a/samples/client/petstore/erlang-client/src/swagger.app.src +++ b/samples/client/petstore/erlang-client/src/petstore.app.src @@ -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 `special-key` 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, []}, diff --git a/samples/client/petstore/erlang-client/src/swagger_api_response.erl b/samples/client/petstore/erlang-client/src/petstore_api_response.erl similarity index 73% rename from samples/client/petstore/erlang-client/src/swagger_api_response.erl rename to samples/client/petstore/erlang-client/src/petstore_api_response.erl index 6457d81358f..20b97ca61c5 100644 --- a/samples/client/petstore/erlang-client/src/swagger_api_response.erl +++ b/samples/client/petstore/erlang-client/src/petstore_api_response.erl @@ -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() diff --git a/samples/client/petstore/erlang-client/src/swagger_category.erl b/samples/client/petstore/erlang-client/src/petstore_category.erl similarity index 67% rename from samples/client/petstore/erlang-client/src/swagger_category.erl rename to samples/client/petstore/erlang-client/src/petstore_category.erl index 7019ba681a8..a7b3e4cb89d 100644 --- a/samples/client/petstore/erlang-client/src/swagger_category.erl +++ b/samples/client/petstore/erlang-client/src/petstore_category.erl @@ -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() }. diff --git a/samples/client/petstore/erlang-client/src/swagger_order.erl b/samples/client/petstore/erlang-client/src/petstore_order.erl similarity index 78% rename from samples/client/petstore/erlang-client/src/swagger_order.erl rename to samples/client/petstore/erlang-client/src/petstore_order.erl index 057727f6cfc..f87a9a1ccd2 100644 --- a/samples/client/petstore/erlang-client/src/swagger_order.erl +++ b/samples/client/petstore/erlang-client/src/petstore_order.erl @@ -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() }. diff --git a/samples/client/petstore/erlang-client/src/swagger_pet.erl b/samples/client/petstore/erlang-client/src/petstore_pet.erl similarity index 78% rename from samples/client/petstore/erlang-client/src/swagger_pet.erl rename to samples/client/petstore/erlang-client/src/petstore_pet.erl index aa7358c46ca..d61eee307e4 100644 --- a/samples/client/petstore/erlang-client/src/swagger_pet.erl +++ b/samples/client/petstore/erlang-client/src/petstore_pet.erl @@ -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(), diff --git a/samples/client/petstore/erlang-client/src/petstore_pet_api.erl b/samples/client/petstore/erlang-client/src/petstore_pet_api.erl new file mode 100644 index 00000000000..440fa9d1b89 --- /dev/null +++ b/samples/client/petstore/erlang-client/src/petstore_pet_api.erl @@ -0,0 +1,145 @@ +-module(petstore_pet_api). + +-export([add_pet/2, add_pet/3, + delete_pet/2, delete_pet/3, + find_pets_by_status/2, find_pets_by_status/3, + find_pets_by_tags/2, find_pets_by_tags/3, + get_pet_by_id/2, get_pet_by_id/3, + update_pet/2, update_pet/3, + update_pet_with_form/2, update_pet_with_form/3, + upload_file/2, upload_file/3]). + +-define(BASE_URL, <<"/v2">>). + +%% @doc Add a new pet to the store +-spec add_pet(ctx:ctx(), petstore_pet:petstore_pet()) -> ok | {error, integer()}. +add_pet(Ctx, Body) -> + add_pet(Ctx, Body, #{}). + +-spec add_pet(ctx:ctx(), petstore_pet:petstore_pet(), maps:map()) -> ok | {error, integer()}. +add_pet(Ctx, Body, _Optional) -> + Method = post, + Path = ["/pet"], + QS = [], + Headers = [], + Body1 = Body, + Opts = [], + + petstore_utils:request(Ctx, Method, [?BASE_URL, Path], QS, Headers, Body1, Opts). + +%% @doc Deletes a pet +-spec delete_pet(ctx:ctx(), integer()) -> ok | {error, integer()}. +delete_pet(Ctx, PetId) -> + delete_pet(Ctx, PetId, #{}). + +-spec delete_pet(ctx:ctx(), integer(), maps:map()) -> ok | {error, integer()}. +delete_pet(Ctx, PetId, _Optional) -> + Method = delete, + Path = ["/pet/", PetId, ""], + QS = [], + Headers = []++[{X, maps:get(X, _Optional)} || X <- ['api_key'], maps:is_key(X, _Optional)], + Body1 = [], + Opts = [], + + petstore_utils:request(Ctx, Method, [?BASE_URL, Path], QS, Headers, Body1, Opts). + +%% @doc Finds Pets by status +%% Multiple status values can be provided with comma separated strings +-spec find_pets_by_status(ctx:ctx(), list()) -> {ok, list(), [petstore_pet:petstore_pet()]} | {error, string()}. +find_pets_by_status(Ctx, Status) -> + find_pets_by_status(Ctx, Status, #{}). + +-spec find_pets_by_status(ctx:ctx(), list(), maps:map()) -> {ok, list(), [petstore_pet:petstore_pet()]} | {error, string()}. +find_pets_by_status(Ctx, Status, _Optional) -> + Method = get, + Path = ["/pet/findByStatus"], + QS = lists:flatten([[{<<"status">>, X} || X <- Status]])++[{X, maps:get(X, _Optional)} || X <- [], maps:is_key(X, _Optional)], + Headers = [], + Body1 = [], + Opts = [], + + petstore_utils:request(Ctx, Method, [?BASE_URL, Path], QS, Headers, Body1, Opts). + +%% @doc Finds Pets by tags +%% Multiple tags can be provided with comma separated strings. Use tag1, tag2, tag3 for testing. +-spec find_pets_by_tags(ctx:ctx(), list()) -> {ok, list(), [petstore_pet:petstore_pet()]} | {error, string()}. +find_pets_by_tags(Ctx, Tags) -> + find_pets_by_tags(Ctx, Tags, #{}). + +-spec find_pets_by_tags(ctx:ctx(), list(), maps:map()) -> {ok, list(), [petstore_pet:petstore_pet()]} | {error, string()}. +find_pets_by_tags(Ctx, Tags, _Optional) -> + Method = get, + Path = ["/pet/findByTags"], + QS = lists:flatten([[{<<"tags">>, X} || X <- Tags]])++[{X, maps:get(X, _Optional)} || X <- [], maps:is_key(X, _Optional)], + Headers = [], + Body1 = [], + Opts = [], + + petstore_utils:request(Ctx, Method, [?BASE_URL, Path], QS, Headers, Body1, Opts). + +%% @doc Find pet by ID +%% Returns a single pet +-spec get_pet_by_id(ctx:ctx(), integer()) -> {ok, list(), petstore_pet:petstore_pet()} | {error, string()}. +get_pet_by_id(Ctx, PetId) -> + get_pet_by_id(Ctx, PetId, #{}). + +-spec get_pet_by_id(ctx:ctx(), integer(), maps:map()) -> {ok, list(), petstore_pet:petstore_pet()} | {error, string()}. +get_pet_by_id(Ctx, PetId, _Optional) -> + Method = get, + Path = ["/pet/", PetId, ""], + QS = [], + Headers = [], + Body1 = [], + Opts = [], + + petstore_utils:request(Ctx, Method, [?BASE_URL, Path], QS, Headers, Body1, Opts). + +%% @doc Update an existing pet +-spec update_pet(ctx:ctx(), petstore_pet:petstore_pet()) -> ok | {error, integer()}. +update_pet(Ctx, Body) -> + update_pet(Ctx, Body, #{}). + +-spec update_pet(ctx:ctx(), petstore_pet:petstore_pet(), maps:map()) -> ok | {error, integer()}. +update_pet(Ctx, Body, _Optional) -> + Method = put, + Path = ["/pet"], + QS = [], + Headers = [], + Body1 = Body, + Opts = [], + + petstore_utils:request(Ctx, Method, [?BASE_URL, Path], QS, Headers, Body1, Opts). + +%% @doc Updates a pet in the store with form data +-spec update_pet_with_form(ctx:ctx(), integer()) -> ok | {error, integer()}. +update_pet_with_form(Ctx, PetId) -> + update_pet_with_form(Ctx, PetId, #{}). + +-spec update_pet_with_form(ctx:ctx(), integer(), maps:map()) -> ok | {error, integer()}. +update_pet_with_form(Ctx, PetId, _Optional) -> + Method = post, + Path = ["/pet/", PetId, ""], + QS = [], + Headers = [], + Body1 = {form, []++[{X, maps:get(X, _Optional)} || X <- ['name', 'status'], maps:is_key(X, _Optional)]}, + Opts = [], + + petstore_utils:request(Ctx, Method, [?BASE_URL, Path], QS, Headers, Body1, Opts). + +%% @doc uploads an image +-spec upload_file(ctx:ctx(), integer()) -> {ok, list(), petstore_api_response:petstore_api_response()} | {error, string()}. +upload_file(Ctx, PetId) -> + upload_file(Ctx, PetId, #{}). + +-spec upload_file(ctx:ctx(), integer(), maps:map()) -> {ok, list(), petstore_api_response:petstore_api_response()} | {error, string()}. +upload_file(Ctx, PetId, _Optional) -> + Method = post, + Path = ["/pet/", PetId, "/uploadImage"], + QS = [], + Headers = [], + Body1 = {form, []++[{X, maps:get(X, _Optional)} || X <- ['additionalMetadata', 'file'], maps:is_key(X, _Optional)]}, + Opts = [], + + petstore_utils:request(Ctx, Method, [?BASE_URL, Path], QS, Headers, Body1, Opts). + + diff --git a/samples/client/petstore/erlang-client/src/petstore_store_api.erl b/samples/client/petstore/erlang-client/src/petstore_store_api.erl new file mode 100644 index 00000000000..454465f8a54 --- /dev/null +++ b/samples/client/petstore/erlang-client/src/petstore_store_api.erl @@ -0,0 +1,77 @@ +-module(petstore_store_api). + +-export([delete_order/2, delete_order/3, + get_inventory/1, get_inventory/2, + get_order_by_id/2, get_order_by_id/3, + place_order/2, place_order/3]). + +-define(BASE_URL, <<"/v2">>). + +%% @doc Delete purchase order by ID +%% For valid response try integer IDs with value < 1000. Anything above 1000 or nonintegers will generate API errors +-spec delete_order(ctx:ctx(), binary()) -> ok | {error, integer()}. +delete_order(Ctx, OrderId) -> + delete_order(Ctx, OrderId, #{}). + +-spec delete_order(ctx:ctx(), binary(), maps:map()) -> ok | {error, integer()}. +delete_order(Ctx, OrderId, _Optional) -> + Method = delete, + Path = ["/store/order/", OrderId, ""], + QS = [], + Headers = [], + Body1 = [], + Opts = [], + + petstore_utils:request(Ctx, Method, [?BASE_URL, Path], QS, Headers, Body1, Opts). + +%% @doc Returns pet inventories by status +%% Returns a map of status codes to quantities +-spec get_inventory(ctx:ctx()) -> {ok, list(), maps:map()} | {error, string()}. +get_inventory(Ctx) -> + get_inventory(Ctx, #{}). + +-spec get_inventory(ctx:ctx(), maps:map()) -> {ok, list(), maps:map()} | {error, string()}. +get_inventory(Ctx, _Optional) -> + Method = get, + Path = ["/store/inventory"], + QS = [], + Headers = [], + Body1 = [], + Opts = [], + + petstore_utils:request(Ctx, Method, [?BASE_URL, Path], QS, Headers, Body1, Opts). + +%% @doc Find purchase order by ID +%% For valid response try integer IDs with value <= 5 or > 10. Other values will generated exceptions +-spec get_order_by_id(ctx:ctx(), integer()) -> {ok, list(), petstore_order:petstore_order()} | {error, string()}. +get_order_by_id(Ctx, OrderId) -> + get_order_by_id(Ctx, OrderId, #{}). + +-spec get_order_by_id(ctx:ctx(), integer(), maps:map()) -> {ok, list(), petstore_order:petstore_order()} | {error, string()}. +get_order_by_id(Ctx, OrderId, _Optional) -> + Method = get, + Path = ["/store/order/", OrderId, ""], + QS = [], + Headers = [], + Body1 = [], + Opts = [], + + petstore_utils:request(Ctx, Method, [?BASE_URL, Path], QS, Headers, Body1, Opts). + +%% @doc Place an order for a pet +-spec place_order(ctx:ctx(), petstore_order:petstore_order()) -> {ok, list(), petstore_order:petstore_order()} | {error, string()}. +place_order(Ctx, Body) -> + place_order(Ctx, Body, #{}). + +-spec place_order(ctx:ctx(), petstore_order:petstore_order(), maps:map()) -> {ok, list(), petstore_order:petstore_order()} | {error, string()}. +place_order(Ctx, Body, _Optional) -> + Method = post, + Path = ["/store/order"], + QS = [], + Headers = [], + Body1 = Body, + Opts = [], + + petstore_utils:request(Ctx, Method, [?BASE_URL, Path], QS, Headers, Body1, Opts). + + diff --git a/samples/client/petstore/erlang-client/src/swagger_tag.erl b/samples/client/petstore/erlang-client/src/petstore_tag.erl similarity index 71% rename from samples/client/petstore/erlang-client/src/swagger_tag.erl rename to samples/client/petstore/erlang-client/src/petstore_tag.erl index 7f8ab49d9c0..02ffc936004 100644 --- a/samples/client/petstore/erlang-client/src/swagger_tag.erl +++ b/samples/client/petstore/erlang-client/src/petstore_tag.erl @@ -1,10 +1,10 @@ --module(swagger_tag). +-module(petstore_tag). -export([encode/1]). --export_type([swagger_tag/0]). +-export_type([petstore_tag/0]). --type swagger_tag() :: +-type petstore_tag() :: #{ 'id' => integer(), 'name' => binary() }. diff --git a/samples/client/petstore/erlang-client/src/swagger_user.erl b/samples/client/petstore/erlang-client/src/petstore_user.erl similarity index 90% rename from samples/client/petstore/erlang-client/src/swagger_user.erl rename to samples/client/petstore/erlang-client/src/petstore_user.erl index e00cb98b1e4..88c19c112f6 100644 --- a/samples/client/petstore/erlang-client/src/swagger_user.erl +++ b/samples/client/petstore/erlang-client/src/petstore_user.erl @@ -1,10 +1,10 @@ --module(swagger_user). +-module(petstore_user). -export([encode/1]). --export_type([swagger_user/0]). +-export_type([petstore_user/0]). --type swagger_user() :: +-type petstore_user() :: #{ 'id' => integer(), 'username' => binary(), 'firstName' => binary(), diff --git a/samples/client/petstore/erlang-client/src/petstore_user_api.erl b/samples/client/petstore/erlang-client/src/petstore_user_api.erl new file mode 100644 index 00000000000..9f46255a085 --- /dev/null +++ b/samples/client/petstore/erlang-client/src/petstore_user_api.erl @@ -0,0 +1,145 @@ +-module(petstore_user_api). + +-export([create_user/2, create_user/3, + create_users_with_array_input/2, create_users_with_array_input/3, + create_users_with_list_input/2, create_users_with_list_input/3, + delete_user/2, delete_user/3, + get_user_by_name/2, get_user_by_name/3, + login_user/3, login_user/4, + logout_user/1, logout_user/2, + update_user/3, update_user/4]). + +-define(BASE_URL, <<"/v2">>). + +%% @doc Create user +%% This can only be done by the logged in user. +-spec create_user(ctx:ctx(), petstore_user:petstore_user()) -> ok | {error, integer()}. +create_user(Ctx, Body) -> + create_user(Ctx, Body, #{}). + +-spec create_user(ctx:ctx(), petstore_user:petstore_user(), maps:map()) -> ok | {error, integer()}. +create_user(Ctx, Body, _Optional) -> + Method = post, + Path = ["/user"], + QS = [], + Headers = [], + Body1 = Body, + Opts = [], + + petstore_utils:request(Ctx, Method, [?BASE_URL, Path], QS, Headers, Body1, Opts). + +%% @doc Creates list of users with given input array +-spec create_users_with_array_input(ctx:ctx(), list()) -> ok | {error, integer()}. +create_users_with_array_input(Ctx, Body) -> + create_users_with_array_input(Ctx, Body, #{}). + +-spec create_users_with_array_input(ctx:ctx(), list(), maps:map()) -> ok | {error, integer()}. +create_users_with_array_input(Ctx, Body, _Optional) -> + Method = post, + Path = ["/user/createWithArray"], + QS = [], + Headers = [], + Body1 = Body, + Opts = [], + + petstore_utils:request(Ctx, Method, [?BASE_URL, Path], QS, Headers, Body1, Opts). + +%% @doc Creates list of users with given input array +-spec create_users_with_list_input(ctx:ctx(), list()) -> ok | {error, integer()}. +create_users_with_list_input(Ctx, Body) -> + create_users_with_list_input(Ctx, Body, #{}). + +-spec create_users_with_list_input(ctx:ctx(), list(), maps:map()) -> ok | {error, integer()}. +create_users_with_list_input(Ctx, Body, _Optional) -> + Method = post, + Path = ["/user/createWithList"], + QS = [], + Headers = [], + Body1 = Body, + Opts = [], + + petstore_utils:request(Ctx, Method, [?BASE_URL, Path], QS, Headers, Body1, Opts). + +%% @doc Delete user +%% This can only be done by the logged in user. +-spec delete_user(ctx:ctx(), binary()) -> ok | {error, integer()}. +delete_user(Ctx, Username) -> + delete_user(Ctx, Username, #{}). + +-spec delete_user(ctx:ctx(), binary(), maps:map()) -> ok | {error, integer()}. +delete_user(Ctx, Username, _Optional) -> + Method = delete, + Path = ["/user/", Username, ""], + QS = [], + Headers = [], + Body1 = [], + Opts = [], + + petstore_utils:request(Ctx, Method, [?BASE_URL, Path], QS, Headers, Body1, Opts). + +%% @doc Get user by user name +-spec get_user_by_name(ctx:ctx(), binary()) -> {ok, list(), petstore_user:petstore_user()} | {error, string()}. +get_user_by_name(Ctx, Username) -> + get_user_by_name(Ctx, Username, #{}). + +-spec get_user_by_name(ctx:ctx(), binary(), maps:map()) -> {ok, list(), petstore_user:petstore_user()} | {error, string()}. +get_user_by_name(Ctx, Username, _Optional) -> + Method = get, + Path = ["/user/", Username, ""], + QS = [], + Headers = [], + Body1 = [], + Opts = [], + + petstore_utils:request(Ctx, Method, [?BASE_URL, Path], QS, Headers, Body1, Opts). + +%% @doc Logs user into the system +-spec login_user(ctx:ctx(), binary(), binary()) -> {ok, list(), binary()} | {error, string()}. +login_user(Ctx, Username, Password) -> + login_user(Ctx, Username, Password, #{}). + +-spec login_user(ctx:ctx(), binary(), binary(), maps:map()) -> {ok, list(), binary()} | {error, string()}. +login_user(Ctx, Username, Password, _Optional) -> + Method = get, + Path = ["/user/login"], + QS = lists:flatten([{<<"username">>, Username}, {<<"password">>, Password}])++[{X, maps:get(X, _Optional)} || X <- [], maps:is_key(X, _Optional)], + Headers = [], + Body1 = [], + Opts = [], + + petstore_utils:request(Ctx, Method, [?BASE_URL, Path], QS, Headers, Body1, Opts). + +%% @doc Logs out current logged in user session +-spec logout_user(ctx:ctx()) -> ok | {error, integer()}. +logout_user(Ctx) -> + logout_user(Ctx, #{}). + +-spec logout_user(ctx:ctx(), maps:map()) -> ok | {error, integer()}. +logout_user(Ctx, _Optional) -> + Method = get, + Path = ["/user/logout"], + QS = [], + Headers = [], + Body1 = [], + Opts = [], + + petstore_utils:request(Ctx, Method, [?BASE_URL, Path], QS, Headers, Body1, Opts). + +%% @doc Updated user +%% This can only be done by the logged in user. +-spec update_user(ctx:ctx(), binary(), petstore_user:petstore_user()) -> ok | {error, integer()}. +update_user(Ctx, Username, Body) -> + update_user(Ctx, Username, Body, #{}). + +-spec update_user(ctx:ctx(), binary(), petstore_user:petstore_user(), maps:map()) -> ok | {error, integer()}. +update_user(Ctx, Username, Body, _Optional) -> + Method = put, + Path = ["/user/", Username, ""], + QS = [], + Headers = [], + Body1 = Body, + Opts = [], + + petstore_utils:request(Ctx, Method, [?BASE_URL, Path], QS, Headers, Body1, Opts). + + diff --git a/samples/client/petstore/erlang-client/src/petstore_utils.erl b/samples/client/petstore/erlang-client/src/petstore_utils.erl new file mode 100644 index 00000000000..32dc14b8e1d --- /dev/null +++ b/samples/client/petstore/erlang-client/src/petstore_utils.erl @@ -0,0 +1,36 @@ +-module(petstore_utils). + +-export([request/7]). + +request(_Ctx, Method, Path, QS, Headers, Body, Opts) -> + Url = hackney_url:make_url(application:get_env(petstore, host, "localhost"), Path, QS), + + Body1 = case lists:keyfind(<<"Content-Type">>, 1, Headers) of + {_, <<"application/json", _/binary>>} -> + jsx:encode(Body); + _ -> + Body + end, + + case hackney:request(Method, Url, Headers, Body1, Opts) of + {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. diff --git a/samples/client/petstore/erlang-client/src/swagger_pet_api.erl b/samples/client/petstore/erlang-client/src/swagger_pet_api.erl deleted file mode 100644 index 7bcf82f2583..00000000000 --- a/samples/client/petstore/erlang-client/src/swagger_pet_api.erl +++ /dev/null @@ -1,197 +0,0 @@ --module(swagger_pet_api). - --export([add_pet/1, add_pet/2, - delete_pet/1, delete_pet/2, - find_pets_by_status/1, find_pets_by_status/2, - find_pets_by_tags/1, find_pets_by_tags/2, - get_pet_by_id/1, get_pet_by_id/2, - update_pet/1, update_pet/2, - update_pet_with_form/1, update_pet_with_form/2, - upload_file/1, upload_file/2]). - --define(BASE_URL, <<"/v2">>). - -%% @doc Add a new pet to the store --spec add_pet(swagger_pet:swagger_pet()) -> ok | {error, integer()}. -add_pet(Body) -> - add_pet(Body, #{}). - --spec add_pet(swagger_pet:swagger_pet(), maps:map()) -> ok | {error, integer()}. -add_pet(Body, _Optional) -> - Method = post, - Path = ["/pet"], - QS = [], - Headers = [], - Body1 = Body, - Opts = [], - Url = hackney_url:make_url(?BASE_URL, Path, QS), - - case hackney:request(Method, Url, Headers, Body1, Opts) of - {ok, 200, _RespHeaders, _ClientRef} -> - ok; - {ok, Status, _RespHeaders, _ClientRef} -> - {error, Status} - end. - -%% @doc Deletes a pet --spec delete_pet(integer()) -> ok | {error, integer()}. -delete_pet(PetId) -> - delete_pet(PetId, #{}). - --spec delete_pet(integer(), maps:map()) -> ok | {error, integer()}. -delete_pet(PetId, _Optional) -> - Method = delete, - Path = ["/pet/", PetId, ""], - QS = [], - Headers = []++[{X, maps:get(X, _Optional)} || X <- ['api_key'], maps:is_key(X, _Optional)], - Body1 = [], - Opts = [], - Url = hackney_url:make_url(?BASE_URL, Path, QS), - - case hackney:request(Method, Url, Headers, Body1, Opts) of - {ok, 200, _RespHeaders, _ClientRef} -> - ok; - {ok, Status, _RespHeaders, _ClientRef} -> - {error, Status} - end. - -%% @doc Finds Pets by status -%% Multiple status values can be provided with comma separated strings --spec find_pets_by_status(list()) -> {ok, list(), [swagger_pet:swagger_pet()]} | {error, string()}. -find_pets_by_status(Status) -> - find_pets_by_status(Status, #{}). - --spec find_pets_by_status(list(), maps:map()) -> {ok, list(), [swagger_pet:swagger_pet()]} | {error, string()}. -find_pets_by_status(Status, _Optional) -> - Method = get, - Path = ["/pet/findByStatus"], - QS = lists:flatten([[{<<"status">>, X} || X <- Status]])++[{X, maps:get(X, _Optional)} || X <- [], maps:is_key(X, _Optional)], - Headers = [], - Body1 = [], - Opts = [], - Url = hackney_url:make_url(?BASE_URL, Path, QS), - - case hackney:request(Method, Url, Headers, Body1, Opts) of - {ok, 200, RespHeaders, ClientRef} -> - {ok, ResponseBody} = hackney:body(ClientRef), - {ok, RespHeaders, jsx:decode(ResponseBody, [return_maps])}; - {ok, 400, _RespHeaders, _ClientRef} -> - {error, "Invalid status value"} - end. - -%% @doc Finds Pets by tags -%% Multiple tags can be provided with comma separated strings. Use tag1, tag2, tag3 for testing. --spec find_pets_by_tags(list()) -> {ok, list(), [swagger_pet:swagger_pet()]} | {error, string()}. -find_pets_by_tags(Tags) -> - find_pets_by_tags(Tags, #{}). - --spec find_pets_by_tags(list(), maps:map()) -> {ok, list(), [swagger_pet:swagger_pet()]} | {error, string()}. -find_pets_by_tags(Tags, _Optional) -> - Method = get, - Path = ["/pet/findByTags"], - QS = lists:flatten([[{<<"tags">>, X} || X <- Tags]])++[{X, maps:get(X, _Optional)} || X <- [], maps:is_key(X, _Optional)], - Headers = [], - Body1 = [], - Opts = [], - Url = hackney_url:make_url(?BASE_URL, Path, QS), - - case hackney:request(Method, Url, Headers, Body1, Opts) of - {ok, 200, RespHeaders, ClientRef} -> - {ok, ResponseBody} = hackney:body(ClientRef), - {ok, RespHeaders, jsx:decode(ResponseBody, [return_maps])}; - {ok, 400, _RespHeaders, _ClientRef} -> - {error, "Invalid tag value"} - end. - -%% @doc Find pet by ID -%% Returns a single pet --spec get_pet_by_id(integer()) -> {ok, list(), swagger_pet:swagger_pet()} | {error, string()}. -get_pet_by_id(PetId) -> - get_pet_by_id(PetId, #{}). - --spec get_pet_by_id(integer(), maps:map()) -> {ok, list(), swagger_pet:swagger_pet()} | {error, string()}. -get_pet_by_id(PetId, _Optional) -> - Method = get, - Path = ["/pet/", PetId, ""], - QS = [], - Headers = [], - Body1 = [], - Opts = [], - Url = hackney_url:make_url(?BASE_URL, Path, QS), - - case hackney:request(Method, Url, Headers, Body1, Opts) of - {ok, 200, RespHeaders, ClientRef} -> - {ok, ResponseBody} = hackney:body(ClientRef), - {ok, RespHeaders, jsx:decode(ResponseBody, [return_maps])}; - {ok, 400, _RespHeaders, _ClientRef} -> - {error, "Invalid ID supplied"}; - {ok, 404, _RespHeaders, _ClientRef} -> - {error, "Pet not found"} - end. - -%% @doc Update an existing pet --spec update_pet(swagger_pet:swagger_pet()) -> ok | {error, integer()}. -update_pet(Body) -> - update_pet(Body, #{}). - --spec update_pet(swagger_pet:swagger_pet(), maps:map()) -> ok | {error, integer()}. -update_pet(Body, _Optional) -> - Method = put, - Path = ["/pet"], - QS = [], - Headers = [], - Body1 = Body, - Opts = [], - Url = hackney_url:make_url(?BASE_URL, Path, QS), - - case hackney:request(Method, Url, Headers, Body1, Opts) of - {ok, 200, _RespHeaders, _ClientRef} -> - ok; - {ok, Status, _RespHeaders, _ClientRef} -> - {error, Status} - end. - -%% @doc Updates a pet in the store with form data --spec update_pet_with_form(integer()) -> ok | {error, integer()}. -update_pet_with_form(PetId) -> - update_pet_with_form(PetId, #{}). - --spec update_pet_with_form(integer(), maps:map()) -> ok | {error, integer()}. -update_pet_with_form(PetId, _Optional) -> - Method = post, - Path = ["/pet/", PetId, ""], - QS = [], - Headers = [], - Body1 = {form, []++[{X, maps:get(X, _Optional)} || X <- ['name', 'status'], maps:is_key(X, _Optional)]}, - Opts = [], - Url = hackney_url:make_url(?BASE_URL, Path, QS), - - case hackney:request(Method, Url, Headers, Body1, Opts) of - {ok, 200, _RespHeaders, _ClientRef} -> - ok; - {ok, Status, _RespHeaders, _ClientRef} -> - {error, Status} - end. - -%% @doc uploads an image --spec upload_file(integer()) -> {ok, list(), swagger_api_response:swagger_api_response()} | {error, string()}. -upload_file(PetId) -> - upload_file(PetId, #{}). - --spec upload_file(integer(), maps:map()) -> {ok, list(), swagger_api_response:swagger_api_response()} | {error, string()}. -upload_file(PetId, _Optional) -> - Method = post, - Path = ["/pet/", PetId, "/uploadImage"], - QS = [], - Headers = [], - Body1 = {form, []++[{X, maps:get(X, _Optional)} || X <- ['additionalMetadata', 'file'], maps:is_key(X, _Optional)]}, - Opts = [], - Url = hackney_url:make_url(?BASE_URL, Path, QS), - - case hackney:request(Method, Url, Headers, Body1, Opts) of - {ok, 200, RespHeaders, ClientRef} -> - {ok, ResponseBody} = hackney:body(ClientRef), - {ok, RespHeaders, jsx:decode(ResponseBody, [return_maps])} - end. - - diff --git a/samples/client/petstore/erlang-client/src/swagger_store_api.erl b/samples/client/petstore/erlang-client/src/swagger_store_api.erl deleted file mode 100644 index 2c04f7049db..00000000000 --- a/samples/client/petstore/erlang-client/src/swagger_store_api.erl +++ /dev/null @@ -1,104 +0,0 @@ --module(swagger_store_api). - --export([delete_order/1, delete_order/2, - get_inventory/0, get_inventory/1, - get_order_by_id/1, get_order_by_id/2, - place_order/1, place_order/2]). - --define(BASE_URL, <<"/v2">>). - -%% @doc Delete purchase order by ID -%% For valid response try integer IDs with value < 1000. Anything above 1000 or nonintegers will generate API errors --spec delete_order(binary()) -> ok | {error, integer()}. -delete_order(OrderId) -> - delete_order(OrderId, #{}). - --spec delete_order(binary(), maps:map()) -> ok | {error, integer()}. -delete_order(OrderId, _Optional) -> - Method = delete, - Path = ["/store/order/", OrderId, ""], - QS = [], - Headers = [], - Body1 = [], - Opts = [], - Url = hackney_url:make_url(?BASE_URL, Path, QS), - - case hackney:request(Method, Url, Headers, Body1, Opts) of - {ok, 200, _RespHeaders, _ClientRef} -> - ok; - {ok, Status, _RespHeaders, _ClientRef} -> - {error, Status} - end. - -%% @doc Returns pet inventories by status -%% Returns a map of status codes to quantities --spec get_inventory() -> {ok, list(), maps:map()} | {error, string()}. -get_inventory() -> - get_inventory(#{}). - --spec get_inventory(maps:map()) -> {ok, list(), maps:map()} | {error, string()}. -get_inventory(_Optional) -> - Method = get, - Path = ["/store/inventory"], - QS = [], - Headers = [], - Body1 = [], - Opts = [], - Url = hackney_url:make_url(?BASE_URL, Path, QS), - - case hackney:request(Method, Url, Headers, Body1, Opts) of - {ok, 200, RespHeaders, ClientRef} -> - {ok, ResponseBody} = hackney:body(ClientRef), - {ok, RespHeaders, jsx:decode(ResponseBody, [return_maps])} - end. - -%% @doc Find purchase order by ID -%% For valid response try integer IDs with value <= 5 or > 10. Other values will generated exceptions --spec get_order_by_id(integer()) -> {ok, list(), swagger_order:swagger_order()} | {error, string()}. -get_order_by_id(OrderId) -> - get_order_by_id(OrderId, #{}). - --spec get_order_by_id(integer(), maps:map()) -> {ok, list(), swagger_order:swagger_order()} | {error, string()}. -get_order_by_id(OrderId, _Optional) -> - Method = get, - Path = ["/store/order/", OrderId, ""], - QS = [], - Headers = [], - Body1 = [], - Opts = [], - Url = hackney_url:make_url(?BASE_URL, Path, QS), - - case hackney:request(Method, Url, Headers, Body1, Opts) of - {ok, 200, RespHeaders, ClientRef} -> - {ok, ResponseBody} = hackney:body(ClientRef), - {ok, RespHeaders, jsx:decode(ResponseBody, [return_maps])}; - {ok, 400, _RespHeaders, _ClientRef} -> - {error, "Invalid ID supplied"}; - {ok, 404, _RespHeaders, _ClientRef} -> - {error, "Order not found"} - end. - -%% @doc Place an order for a pet --spec place_order(swagger_order:swagger_order()) -> {ok, list(), swagger_order:swagger_order()} | {error, string()}. -place_order(Body) -> - place_order(Body, #{}). - --spec place_order(swagger_order:swagger_order(), maps:map()) -> {ok, list(), swagger_order:swagger_order()} | {error, string()}. -place_order(Body, _Optional) -> - Method = post, - Path = ["/store/order"], - QS = [], - Headers = [], - Body1 = Body, - Opts = [], - Url = hackney_url:make_url(?BASE_URL, Path, QS), - - case hackney:request(Method, Url, Headers, Body1, Opts) of - {ok, 200, RespHeaders, ClientRef} -> - {ok, ResponseBody} = hackney:body(ClientRef), - {ok, RespHeaders, jsx:decode(ResponseBody, [return_maps])}; - {ok, 400, _RespHeaders, _ClientRef} -> - {error, "Invalid Order"} - end. - - diff --git a/samples/client/petstore/erlang-client/src/swagger_user_api.erl b/samples/client/petstore/erlang-client/src/swagger_user_api.erl deleted file mode 100644 index 215bf9df11d..00000000000 --- a/samples/client/petstore/erlang-client/src/swagger_user_api.erl +++ /dev/null @@ -1,197 +0,0 @@ --module(swagger_user_api). - --export([create_user/1, create_user/2, - create_users_with_array_input/1, create_users_with_array_input/2, - create_users_with_list_input/1, create_users_with_list_input/2, - delete_user/1, delete_user/2, - get_user_by_name/1, get_user_by_name/2, - login_user/2, login_user/3, - logout_user/0, logout_user/1, - update_user/2, update_user/3]). - --define(BASE_URL, <<"/v2">>). - -%% @doc Create user -%% This can only be done by the logged in user. --spec create_user(swagger_user:swagger_user()) -> ok | {error, integer()}. -create_user(Body) -> - create_user(Body, #{}). - --spec create_user(swagger_user:swagger_user(), maps:map()) -> ok | {error, integer()}. -create_user(Body, _Optional) -> - Method = post, - Path = ["/user"], - QS = [], - Headers = [], - Body1 = Body, - Opts = [], - Url = hackney_url:make_url(?BASE_URL, Path, QS), - - case hackney:request(Method, Url, Headers, Body1, Opts) of - {ok, 200, _RespHeaders, _ClientRef} -> - ok; - {ok, Status, _RespHeaders, _ClientRef} -> - {error, Status} - end. - -%% @doc Creates list of users with given input array --spec create_users_with_array_input(list()) -> ok | {error, integer()}. -create_users_with_array_input(Body) -> - create_users_with_array_input(Body, #{}). - --spec create_users_with_array_input(list(), maps:map()) -> ok | {error, integer()}. -create_users_with_array_input(Body, _Optional) -> - Method = post, - Path = ["/user/createWithArray"], - QS = [], - Headers = [], - Body1 = Body, - Opts = [], - Url = hackney_url:make_url(?BASE_URL, Path, QS), - - case hackney:request(Method, Url, Headers, Body1, Opts) of - {ok, 200, _RespHeaders, _ClientRef} -> - ok; - {ok, Status, _RespHeaders, _ClientRef} -> - {error, Status} - end. - -%% @doc Creates list of users with given input array --spec create_users_with_list_input(list()) -> ok | {error, integer()}. -create_users_with_list_input(Body) -> - create_users_with_list_input(Body, #{}). - --spec create_users_with_list_input(list(), maps:map()) -> ok | {error, integer()}. -create_users_with_list_input(Body, _Optional) -> - Method = post, - Path = ["/user/createWithList"], - QS = [], - Headers = [], - Body1 = Body, - Opts = [], - Url = hackney_url:make_url(?BASE_URL, Path, QS), - - case hackney:request(Method, Url, Headers, Body1, Opts) of - {ok, 200, _RespHeaders, _ClientRef} -> - ok; - {ok, Status, _RespHeaders, _ClientRef} -> - {error, Status} - end. - -%% @doc Delete user -%% This can only be done by the logged in user. --spec delete_user(binary()) -> ok | {error, integer()}. -delete_user(Username) -> - delete_user(Username, #{}). - --spec delete_user(binary(), maps:map()) -> ok | {error, integer()}. -delete_user(Username, _Optional) -> - Method = delete, - Path = ["/user/", Username, ""], - QS = [], - Headers = [], - Body1 = [], - Opts = [], - Url = hackney_url:make_url(?BASE_URL, Path, QS), - - case hackney:request(Method, Url, Headers, Body1, Opts) of - {ok, 200, _RespHeaders, _ClientRef} -> - ok; - {ok, Status, _RespHeaders, _ClientRef} -> - {error, Status} - end. - -%% @doc Get user by user name --spec get_user_by_name(binary()) -> {ok, list(), swagger_user:swagger_user()} | {error, string()}. -get_user_by_name(Username) -> - get_user_by_name(Username, #{}). - --spec get_user_by_name(binary(), maps:map()) -> {ok, list(), swagger_user:swagger_user()} | {error, string()}. -get_user_by_name(Username, _Optional) -> - Method = get, - Path = ["/user/", Username, ""], - QS = [], - Headers = [], - Body1 = [], - Opts = [], - Url = hackney_url:make_url(?BASE_URL, Path, QS), - - case hackney:request(Method, Url, Headers, Body1, Opts) of - {ok, 200, RespHeaders, ClientRef} -> - {ok, ResponseBody} = hackney:body(ClientRef), - {ok, RespHeaders, jsx:decode(ResponseBody, [return_maps])}; - {ok, 400, _RespHeaders, _ClientRef} -> - {error, "Invalid username supplied"}; - {ok, 404, _RespHeaders, _ClientRef} -> - {error, "User not found"} - end. - -%% @doc Logs user into the system --spec login_user(binary(), binary()) -> {ok, list(), binary()} | {error, string()}. -login_user(Username, Password) -> - login_user(Username, Password, #{}). - --spec login_user(binary(), binary(), maps:map()) -> {ok, list(), binary()} | {error, string()}. -login_user(Username, Password, _Optional) -> - Method = get, - Path = ["/user/login"], - QS = lists:flatten([{<<"username">>, Username}, {<<"password">>, Password}])++[{X, maps:get(X, _Optional)} || X <- [], maps:is_key(X, _Optional)], - Headers = [], - Body1 = [], - Opts = [], - Url = hackney_url:make_url(?BASE_URL, Path, QS), - - case hackney:request(Method, Url, Headers, Body1, Opts) of - {ok, 200, RespHeaders, ClientRef} -> - {ok, ResponseBody} = hackney:body(ClientRef), - {ok, RespHeaders, jsx:decode(ResponseBody, [return_maps])}; - {ok, 400, _RespHeaders, _ClientRef} -> - {error, "Invalid username/password supplied"} - end. - -%% @doc Logs out current logged in user session --spec logout_user() -> ok | {error, integer()}. -logout_user() -> - logout_user(#{}). - --spec logout_user(maps:map()) -> ok | {error, integer()}. -logout_user(_Optional) -> - Method = get, - Path = ["/user/logout"], - QS = [], - Headers = [], - Body1 = [], - Opts = [], - Url = hackney_url:make_url(?BASE_URL, Path, QS), - - case hackney:request(Method, Url, Headers, Body1, Opts) of - {ok, 200, _RespHeaders, _ClientRef} -> - ok; - {ok, Status, _RespHeaders, _ClientRef} -> - {error, Status} - end. - -%% @doc Updated user -%% This can only be done by the logged in user. --spec update_user(binary(), swagger_user:swagger_user()) -> ok | {error, integer()}. -update_user(Username, Body) -> - update_user(Username, Body, #{}). - --spec update_user(binary(), swagger_user:swagger_user(), maps:map()) -> ok | {error, integer()}. -update_user(Username, Body, _Optional) -> - Method = put, - Path = ["/user/", Username, ""], - QS = [], - Headers = [], - Body1 = Body, - Opts = [], - Url = hackney_url:make_url(?BASE_URL, Path, QS), - - case hackney:request(Method, Url, Headers, Body1, Opts) of - {ok, 200, _RespHeaders, _ClientRef} -> - ok; - {ok, Status, _RespHeaders, _ClientRef} -> - {error, Status} - end. - - From af0b9b0091faaef2959fb623214d44563a878b6c Mon Sep 17 00:00:00 2001 From: Tristan Sloughter Date: Tue, 26 Dec 2017 11:50:02 -0800 Subject: [PATCH 3/5] [erlang-client] add support for passing http client configuration to requests --- .../main/resources/erlang-client/api.mustache | 18 ++-- .../resources/erlang-client/utils.mustache | 48 ++++++++++ .../erlang-client/.swagger-codegen/VERSION | 2 +- .../erlang-client/src/petstore_pet_api.erl | 90 +++++++++++-------- .../erlang-client/src/petstore_store_api.erl | 40 +++++---- .../erlang-client/src/petstore_user_api.erl | 82 ++++++++++------- .../erlang-client/src/petstore_utils.erl | 14 ++- 7 files changed, 198 insertions(+), 96 deletions(-) create mode 100644 modules/swagger-codegen/src/main/resources/erlang-client/utils.mustache diff --git a/modules/swagger-codegen/src/main/resources/erlang-client/api.mustache b/modules/swagger-codegen/src/main/resources/erlang-client/api.mustache index 4e2e26d0c10..d91c838f125 100644 --- a/modules/swagger-codegen/src/main/resources/erlang-client/api.mustache +++ b/modules/swagger-codegen/src/main/resources/erlang-client/api.mustache @@ -3,7 +3,7 @@ -export([{{#operations}}{{#operation}}{{^-first}}, {{/-first}}{{operationId}}/{{arityRequired}}, {{operationId}}/{{arityOptional}}{{/operation}}{{/operations}}]). --define(BASE_URL, <<"{{{basePathWithoutHost}}}">>). +-define(BASE_URL, "{{{basePathWithoutHost}}}"). {{#operations}} {{#operation}} @@ -11,18 +11,20 @@ {{^notes.isEmpty}} %% {{{notes}}} {{/notes.isEmpty}} --spec {{operationId}}(ctx:ctx(){{#allParams}}{{#required}}, {{{dataType}}}{{/required}}{{/allParams}}) -> {{#returnType}}{ok, list(), {{{returnType}}}} | {error, string()}{{/returnType}}{{^returnType}}ok | {error, integer()}{{/returnType}}. +-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()) -> {{#returnType}}{ok, list(), {{{returnType}}}} | {error, string()}{{/returnType}}{{^returnType}}ok | {error, integer()}{{/returnType}}. -{{operationId}}(Ctx{{#allParams}}{{#required}}, {{paramName}}{{/required}}{{/allParams}}, _Optional) -> +-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, #{}), + 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 = [], + 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}}, + Opts = maps:get(hackney_opts, Optional, []), {{packageName}}_utils:request(Ctx, Method, [?BASE_URL, Path], QS, Headers, Body1, Opts). diff --git a/modules/swagger-codegen/src/main/resources/erlang-client/utils.mustache b/modules/swagger-codegen/src/main/resources/erlang-client/utils.mustache new file mode 100644 index 00000000000..2f2f100b71e --- /dev/null +++ b/modules/swagger-codegen/src/main/resources/erlang-client/utils.mustache @@ -0,0 +1,48 @@ +-module({{packageName}}_utils). + +-export([request/7, + optional_params/2]). + +-type response_info() :: #{status := integer(), + headers := list()}. +-export_type([response_info/0]). + +request(_Ctx, Method, Path, QS, Headers, Body, Opts) -> + Url = hackney_url:make_url(application:get_env({{packageName}}, host, "localhost"), Path, QS), + + Body1 = case lists:keyfind(<<"Content-Type">>, 1, Headers) of + {_, <<"application/json", _/binary>>} -> + jsx:encode(Body); + _ -> + Body + end, + + case hackney:request(Method, Url, Headers, Body1, Opts) 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)]. \ No newline at end of file diff --git a/samples/client/petstore/erlang-client/.swagger-codegen/VERSION b/samples/client/petstore/erlang-client/.swagger-codegen/VERSION index f9f7450d135..cc6612c36e0 100644 --- a/samples/client/petstore/erlang-client/.swagger-codegen/VERSION +++ b/samples/client/petstore/erlang-client/.swagger-codegen/VERSION @@ -1 +1 @@ -2.3.0-SNAPSHOT \ No newline at end of file +2.3.0 \ No newline at end of file diff --git a/samples/client/petstore/erlang-client/src/petstore_pet_api.erl b/samples/client/petstore/erlang-client/src/petstore_pet_api.erl index 440fa9d1b89..d09a3748cf1 100644 --- a/samples/client/petstore/erlang-client/src/petstore_pet_api.erl +++ b/samples/client/petstore/erlang-client/src/petstore_pet_api.erl @@ -12,133 +12,149 @@ -define(BASE_URL, <<"/v2">>). %% @doc Add a new pet to the store --spec add_pet(ctx:ctx(), petstore_pet:petstore_pet()) -> ok | {error, integer()}. +-spec add_pet(ctx:ctx(), petstore_pet:petstore_pet()) -> {ok, [], petstore_utils:response_info()} | {ok, hackney:client_ref()} | {error, term(), petstore_utils:response_info()}. add_pet(Ctx, Body) -> add_pet(Ctx, Body, #{}). --spec add_pet(ctx:ctx(), petstore_pet:petstore_pet(), maps:map()) -> ok | {error, integer()}. -add_pet(Ctx, Body, _Optional) -> +-spec add_pet(ctx:ctx(), petstore_pet:petstore_pet(), maps:map()) -> {ok, [], petstore_utils:response_info()} | {ok, hackney:client_ref()} | {error, term(), petstore_utils:response_info()}. +add_pet(Ctx, Body, Optional) -> + _OptionalParams = maps:get(params, Optional, #{}), + Method = post, Path = ["/pet"], QS = [], Headers = [], Body1 = Body, - Opts = [], + Opts = maps:get(hackney_opts, Optional, []), petstore_utils:request(Ctx, Method, [?BASE_URL, Path], QS, Headers, Body1, Opts). %% @doc Deletes a pet --spec delete_pet(ctx:ctx(), integer()) -> ok | {error, integer()}. +-spec delete_pet(ctx:ctx(), integer()) -> {ok, [], petstore_utils:response_info()} | {ok, hackney:client_ref()} | {error, term(), petstore_utils:response_info()}. delete_pet(Ctx, PetId) -> delete_pet(Ctx, PetId, #{}). --spec delete_pet(ctx:ctx(), integer(), maps:map()) -> ok | {error, integer()}. -delete_pet(Ctx, PetId, _Optional) -> +-spec delete_pet(ctx:ctx(), integer(), maps:map()) -> {ok, [], petstore_utils:response_info()} | {ok, hackney:client_ref()} | {error, term(), petstore_utils:response_info()}. +delete_pet(Ctx, PetId, Optional) -> + _OptionalParams = maps:get(params, Optional, #{}), + Method = delete, Path = ["/pet/", PetId, ""], QS = [], - Headers = []++[{X, maps:get(X, _Optional)} || X <- ['api_key'], maps:is_key(X, _Optional)], + Headers = []++petstore_utils:optional_params(['api_key'], _OptionalParams), Body1 = [], - Opts = [], + Opts = maps:get(hackney_opts, Optional, []), petstore_utils:request(Ctx, Method, [?BASE_URL, Path], QS, Headers, Body1, Opts). %% @doc Finds Pets by status %% Multiple status values can be provided with comma separated strings --spec find_pets_by_status(ctx:ctx(), list()) -> {ok, list(), [petstore_pet:petstore_pet()]} | {error, string()}. +-spec find_pets_by_status(ctx:ctx(), list()) -> {ok, [petstore_pet:petstore_pet()], petstore_utils:response_info()} | {ok, hackney:client_ref()} | {error, term(), petstore_utils:response_info()}. find_pets_by_status(Ctx, Status) -> find_pets_by_status(Ctx, Status, #{}). --spec find_pets_by_status(ctx:ctx(), list(), maps:map()) -> {ok, list(), [petstore_pet:petstore_pet()]} | {error, string()}. -find_pets_by_status(Ctx, Status, _Optional) -> +-spec find_pets_by_status(ctx:ctx(), list(), maps:map()) -> {ok, [petstore_pet:petstore_pet()], petstore_utils:response_info()} | {ok, hackney:client_ref()} | {error, term(), petstore_utils:response_info()}. +find_pets_by_status(Ctx, Status, Optional) -> + _OptionalParams = maps:get(params, Optional, #{}), + Method = get, Path = ["/pet/findByStatus"], - QS = lists:flatten([[{<<"status">>, X} || X <- Status]])++[{X, maps:get(X, _Optional)} || X <- [], maps:is_key(X, _Optional)], + QS = lists:flatten([[{<<"status">>, X} || X <- Status]])++petstore_utils:optional_params([], _OptionalParams), Headers = [], Body1 = [], - Opts = [], + Opts = maps:get(hackney_opts, Optional, []), petstore_utils:request(Ctx, Method, [?BASE_URL, Path], QS, Headers, Body1, Opts). %% @doc Finds Pets by tags %% Multiple tags can be provided with comma separated strings. Use tag1, tag2, tag3 for testing. --spec find_pets_by_tags(ctx:ctx(), list()) -> {ok, list(), [petstore_pet:petstore_pet()]} | {error, string()}. +-spec find_pets_by_tags(ctx:ctx(), list()) -> {ok, [petstore_pet:petstore_pet()], petstore_utils:response_info()} | {ok, hackney:client_ref()} | {error, term(), petstore_utils:response_info()}. find_pets_by_tags(Ctx, Tags) -> find_pets_by_tags(Ctx, Tags, #{}). --spec find_pets_by_tags(ctx:ctx(), list(), maps:map()) -> {ok, list(), [petstore_pet:petstore_pet()]} | {error, string()}. -find_pets_by_tags(Ctx, Tags, _Optional) -> +-spec find_pets_by_tags(ctx:ctx(), list(), maps:map()) -> {ok, [petstore_pet:petstore_pet()], petstore_utils:response_info()} | {ok, hackney:client_ref()} | {error, term(), petstore_utils:response_info()}. +find_pets_by_tags(Ctx, Tags, Optional) -> + _OptionalParams = maps:get(params, Optional, #{}), + Method = get, Path = ["/pet/findByTags"], - QS = lists:flatten([[{<<"tags">>, X} || X <- Tags]])++[{X, maps:get(X, _Optional)} || X <- [], maps:is_key(X, _Optional)], + QS = lists:flatten([[{<<"tags">>, X} || X <- Tags]])++petstore_utils:optional_params([], _OptionalParams), Headers = [], Body1 = [], - Opts = [], + Opts = maps:get(hackney_opts, Optional, []), petstore_utils:request(Ctx, Method, [?BASE_URL, Path], QS, Headers, Body1, Opts). %% @doc Find pet by ID %% Returns a single pet --spec get_pet_by_id(ctx:ctx(), integer()) -> {ok, list(), petstore_pet:petstore_pet()} | {error, string()}. +-spec get_pet_by_id(ctx:ctx(), integer()) -> {ok, petstore_pet:petstore_pet(), petstore_utils:response_info()} | {ok, hackney:client_ref()} | {error, term(), petstore_utils:response_info()}. get_pet_by_id(Ctx, PetId) -> get_pet_by_id(Ctx, PetId, #{}). --spec get_pet_by_id(ctx:ctx(), integer(), maps:map()) -> {ok, list(), petstore_pet:petstore_pet()} | {error, string()}. -get_pet_by_id(Ctx, PetId, _Optional) -> +-spec get_pet_by_id(ctx:ctx(), integer(), maps:map()) -> {ok, petstore_pet:petstore_pet(), petstore_utils:response_info()} | {ok, hackney:client_ref()} | {error, term(), petstore_utils:response_info()}. +get_pet_by_id(Ctx, PetId, Optional) -> + _OptionalParams = maps:get(params, Optional, #{}), + Method = get, Path = ["/pet/", PetId, ""], QS = [], Headers = [], Body1 = [], - Opts = [], + Opts = maps:get(hackney_opts, Optional, []), petstore_utils:request(Ctx, Method, [?BASE_URL, Path], QS, Headers, Body1, Opts). %% @doc Update an existing pet --spec update_pet(ctx:ctx(), petstore_pet:petstore_pet()) -> ok | {error, integer()}. +-spec update_pet(ctx:ctx(), petstore_pet:petstore_pet()) -> {ok, [], petstore_utils:response_info()} | {ok, hackney:client_ref()} | {error, term(), petstore_utils:response_info()}. update_pet(Ctx, Body) -> update_pet(Ctx, Body, #{}). --spec update_pet(ctx:ctx(), petstore_pet:petstore_pet(), maps:map()) -> ok | {error, integer()}. -update_pet(Ctx, Body, _Optional) -> +-spec update_pet(ctx:ctx(), petstore_pet:petstore_pet(), maps:map()) -> {ok, [], petstore_utils:response_info()} | {ok, hackney:client_ref()} | {error, term(), petstore_utils:response_info()}. +update_pet(Ctx, Body, Optional) -> + _OptionalParams = maps:get(params, Optional, #{}), + Method = put, Path = ["/pet"], QS = [], Headers = [], Body1 = Body, - Opts = [], + Opts = maps:get(hackney_opts, Optional, []), petstore_utils:request(Ctx, Method, [?BASE_URL, Path], QS, Headers, Body1, Opts). %% @doc Updates a pet in the store with form data --spec update_pet_with_form(ctx:ctx(), integer()) -> ok | {error, integer()}. +-spec update_pet_with_form(ctx:ctx(), integer()) -> {ok, [], petstore_utils:response_info()} | {ok, hackney:client_ref()} | {error, term(), petstore_utils:response_info()}. update_pet_with_form(Ctx, PetId) -> update_pet_with_form(Ctx, PetId, #{}). --spec update_pet_with_form(ctx:ctx(), integer(), maps:map()) -> ok | {error, integer()}. -update_pet_with_form(Ctx, PetId, _Optional) -> +-spec update_pet_with_form(ctx:ctx(), integer(), maps:map()) -> {ok, [], petstore_utils:response_info()} | {ok, hackney:client_ref()} | {error, term(), petstore_utils:response_info()}. +update_pet_with_form(Ctx, PetId, Optional) -> + _OptionalParams = maps:get(params, Optional, #{}), + Method = post, Path = ["/pet/", PetId, ""], QS = [], Headers = [], - Body1 = {form, []++[{X, maps:get(X, _Optional)} || X <- ['name', 'status'], maps:is_key(X, _Optional)]}, - Opts = [], + Body1 = {form, []++petstore_utils:optional_params(['name', 'status'], _OptionalParams)}, + Opts = maps:get(hackney_opts, Optional, []), petstore_utils:request(Ctx, Method, [?BASE_URL, Path], QS, Headers, Body1, Opts). %% @doc uploads an image --spec upload_file(ctx:ctx(), integer()) -> {ok, list(), petstore_api_response:petstore_api_response()} | {error, string()}. +-spec upload_file(ctx:ctx(), integer()) -> {ok, petstore_api_response:petstore_api_response(), petstore_utils:response_info()} | {ok, hackney:client_ref()} | {error, term(), petstore_utils:response_info()}. upload_file(Ctx, PetId) -> upload_file(Ctx, PetId, #{}). --spec upload_file(ctx:ctx(), integer(), maps:map()) -> {ok, list(), petstore_api_response:petstore_api_response()} | {error, string()}. -upload_file(Ctx, PetId, _Optional) -> +-spec upload_file(ctx:ctx(), integer(), maps:map()) -> {ok, petstore_api_response:petstore_api_response(), petstore_utils:response_info()} | {ok, hackney:client_ref()} | {error, term(), petstore_utils:response_info()}. +upload_file(Ctx, PetId, Optional) -> + _OptionalParams = maps:get(params, Optional, #{}), + Method = post, Path = ["/pet/", PetId, "/uploadImage"], QS = [], Headers = [], - Body1 = {form, []++[{X, maps:get(X, _Optional)} || X <- ['additionalMetadata', 'file'], maps:is_key(X, _Optional)]}, - Opts = [], + Body1 = {form, []++petstore_utils:optional_params(['additionalMetadata', 'file'], _OptionalParams)}, + Opts = maps:get(hackney_opts, Optional, []), petstore_utils:request(Ctx, Method, [?BASE_URL, Path], QS, Headers, Body1, Opts). diff --git a/samples/client/petstore/erlang-client/src/petstore_store_api.erl b/samples/client/petstore/erlang-client/src/petstore_store_api.erl index 454465f8a54..c752632a073 100644 --- a/samples/client/petstore/erlang-client/src/petstore_store_api.erl +++ b/samples/client/petstore/erlang-client/src/petstore_store_api.erl @@ -9,68 +9,76 @@ %% @doc Delete purchase order by ID %% For valid response try integer IDs with value < 1000. Anything above 1000 or nonintegers will generate API errors --spec delete_order(ctx:ctx(), binary()) -> ok | {error, integer()}. +-spec delete_order(ctx:ctx(), binary()) -> {ok, [], petstore_utils:response_info()} | {ok, hackney:client_ref()} | {error, term(), petstore_utils:response_info()}. delete_order(Ctx, OrderId) -> delete_order(Ctx, OrderId, #{}). --spec delete_order(ctx:ctx(), binary(), maps:map()) -> ok | {error, integer()}. -delete_order(Ctx, OrderId, _Optional) -> +-spec delete_order(ctx:ctx(), binary(), maps:map()) -> {ok, [], petstore_utils:response_info()} | {ok, hackney:client_ref()} | {error, term(), petstore_utils:response_info()}. +delete_order(Ctx, OrderId, Optional) -> + _OptionalParams = maps:get(params, Optional, #{}), + Method = delete, Path = ["/store/order/", OrderId, ""], QS = [], Headers = [], Body1 = [], - Opts = [], + Opts = maps:get(hackney_opts, Optional, []), petstore_utils:request(Ctx, Method, [?BASE_URL, Path], QS, Headers, Body1, Opts). %% @doc Returns pet inventories by status %% Returns a map of status codes to quantities --spec get_inventory(ctx:ctx()) -> {ok, list(), maps:map()} | {error, string()}. +-spec get_inventory(ctx:ctx()) -> {ok, maps:map(), petstore_utils:response_info()} | {ok, hackney:client_ref()} | {error, term(), petstore_utils:response_info()}. get_inventory(Ctx) -> get_inventory(Ctx, #{}). --spec get_inventory(ctx:ctx(), maps:map()) -> {ok, list(), maps:map()} | {error, string()}. -get_inventory(Ctx, _Optional) -> +-spec get_inventory(ctx:ctx(), maps:map()) -> {ok, maps:map(), petstore_utils:response_info()} | {ok, hackney:client_ref()} | {error, term(), petstore_utils:response_info()}. +get_inventory(Ctx, Optional) -> + _OptionalParams = maps:get(params, Optional, #{}), + Method = get, Path = ["/store/inventory"], QS = [], Headers = [], Body1 = [], - Opts = [], + Opts = maps:get(hackney_opts, Optional, []), petstore_utils:request(Ctx, Method, [?BASE_URL, Path], QS, Headers, Body1, Opts). %% @doc Find purchase order by ID %% For valid response try integer IDs with value <= 5 or > 10. Other values will generated exceptions --spec get_order_by_id(ctx:ctx(), integer()) -> {ok, list(), petstore_order:petstore_order()} | {error, string()}. +-spec get_order_by_id(ctx:ctx(), integer()) -> {ok, petstore_order:petstore_order(), petstore_utils:response_info()} | {ok, hackney:client_ref()} | {error, term(), petstore_utils:response_info()}. get_order_by_id(Ctx, OrderId) -> get_order_by_id(Ctx, OrderId, #{}). --spec get_order_by_id(ctx:ctx(), integer(), maps:map()) -> {ok, list(), petstore_order:petstore_order()} | {error, string()}. -get_order_by_id(Ctx, OrderId, _Optional) -> +-spec get_order_by_id(ctx:ctx(), integer(), maps:map()) -> {ok, petstore_order:petstore_order(), petstore_utils:response_info()} | {ok, hackney:client_ref()} | {error, term(), petstore_utils:response_info()}. +get_order_by_id(Ctx, OrderId, Optional) -> + _OptionalParams = maps:get(params, Optional, #{}), + Method = get, Path = ["/store/order/", OrderId, ""], QS = [], Headers = [], Body1 = [], - Opts = [], + Opts = maps:get(hackney_opts, Optional, []), petstore_utils:request(Ctx, Method, [?BASE_URL, Path], QS, Headers, Body1, Opts). %% @doc Place an order for a pet --spec place_order(ctx:ctx(), petstore_order:petstore_order()) -> {ok, list(), petstore_order:petstore_order()} | {error, string()}. +-spec place_order(ctx:ctx(), petstore_order:petstore_order()) -> {ok, petstore_order:petstore_order(), petstore_utils:response_info()} | {ok, hackney:client_ref()} | {error, term(), petstore_utils:response_info()}. place_order(Ctx, Body) -> place_order(Ctx, Body, #{}). --spec place_order(ctx:ctx(), petstore_order:petstore_order(), maps:map()) -> {ok, list(), petstore_order:petstore_order()} | {error, string()}. -place_order(Ctx, Body, _Optional) -> +-spec place_order(ctx:ctx(), petstore_order:petstore_order(), maps:map()) -> {ok, petstore_order:petstore_order(), petstore_utils:response_info()} | {ok, hackney:client_ref()} | {error, term(), petstore_utils:response_info()}. +place_order(Ctx, Body, Optional) -> + _OptionalParams = maps:get(params, Optional, #{}), + Method = post, Path = ["/store/order"], QS = [], Headers = [], Body1 = Body, - Opts = [], + Opts = maps:get(hackney_opts, Optional, []), petstore_utils:request(Ctx, Method, [?BASE_URL, Path], QS, Headers, Body1, Opts). diff --git a/samples/client/petstore/erlang-client/src/petstore_user_api.erl b/samples/client/petstore/erlang-client/src/petstore_user_api.erl index 9f46255a085..5405c236ff2 100644 --- a/samples/client/petstore/erlang-client/src/petstore_user_api.erl +++ b/samples/client/petstore/erlang-client/src/petstore_user_api.erl @@ -13,132 +13,148 @@ %% @doc Create user %% This can only be done by the logged in user. --spec create_user(ctx:ctx(), petstore_user:petstore_user()) -> ok | {error, integer()}. +-spec create_user(ctx:ctx(), petstore_user:petstore_user()) -> {ok, [], petstore_utils:response_info()} | {ok, hackney:client_ref()} | {error, term(), petstore_utils:response_info()}. create_user(Ctx, Body) -> create_user(Ctx, Body, #{}). --spec create_user(ctx:ctx(), petstore_user:petstore_user(), maps:map()) -> ok | {error, integer()}. -create_user(Ctx, Body, _Optional) -> +-spec create_user(ctx:ctx(), petstore_user:petstore_user(), maps:map()) -> {ok, [], petstore_utils:response_info()} | {ok, hackney:client_ref()} | {error, term(), petstore_utils:response_info()}. +create_user(Ctx, Body, Optional) -> + _OptionalParams = maps:get(params, Optional, #{}), + Method = post, Path = ["/user"], QS = [], Headers = [], Body1 = Body, - Opts = [], + Opts = maps:get(hackney_opts, Optional, []), petstore_utils:request(Ctx, Method, [?BASE_URL, Path], QS, Headers, Body1, Opts). %% @doc Creates list of users with given input array --spec create_users_with_array_input(ctx:ctx(), list()) -> ok | {error, integer()}. +-spec create_users_with_array_input(ctx:ctx(), list()) -> {ok, [], petstore_utils:response_info()} | {ok, hackney:client_ref()} | {error, term(), petstore_utils:response_info()}. create_users_with_array_input(Ctx, Body) -> create_users_with_array_input(Ctx, Body, #{}). --spec create_users_with_array_input(ctx:ctx(), list(), maps:map()) -> ok | {error, integer()}. -create_users_with_array_input(Ctx, Body, _Optional) -> +-spec create_users_with_array_input(ctx:ctx(), list(), maps:map()) -> {ok, [], petstore_utils:response_info()} | {ok, hackney:client_ref()} | {error, term(), petstore_utils:response_info()}. +create_users_with_array_input(Ctx, Body, Optional) -> + _OptionalParams = maps:get(params, Optional, #{}), + Method = post, Path = ["/user/createWithArray"], QS = [], Headers = [], Body1 = Body, - Opts = [], + Opts = maps:get(hackney_opts, Optional, []), petstore_utils:request(Ctx, Method, [?BASE_URL, Path], QS, Headers, Body1, Opts). %% @doc Creates list of users with given input array --spec create_users_with_list_input(ctx:ctx(), list()) -> ok | {error, integer()}. +-spec create_users_with_list_input(ctx:ctx(), list()) -> {ok, [], petstore_utils:response_info()} | {ok, hackney:client_ref()} | {error, term(), petstore_utils:response_info()}. create_users_with_list_input(Ctx, Body) -> create_users_with_list_input(Ctx, Body, #{}). --spec create_users_with_list_input(ctx:ctx(), list(), maps:map()) -> ok | {error, integer()}. -create_users_with_list_input(Ctx, Body, _Optional) -> +-spec create_users_with_list_input(ctx:ctx(), list(), maps:map()) -> {ok, [], petstore_utils:response_info()} | {ok, hackney:client_ref()} | {error, term(), petstore_utils:response_info()}. +create_users_with_list_input(Ctx, Body, Optional) -> + _OptionalParams = maps:get(params, Optional, #{}), + Method = post, Path = ["/user/createWithList"], QS = [], Headers = [], Body1 = Body, - Opts = [], + Opts = maps:get(hackney_opts, Optional, []), petstore_utils:request(Ctx, Method, [?BASE_URL, Path], QS, Headers, Body1, Opts). %% @doc Delete user %% This can only be done by the logged in user. --spec delete_user(ctx:ctx(), binary()) -> ok | {error, integer()}. +-spec delete_user(ctx:ctx(), binary()) -> {ok, [], petstore_utils:response_info()} | {ok, hackney:client_ref()} | {error, term(), petstore_utils:response_info()}. delete_user(Ctx, Username) -> delete_user(Ctx, Username, #{}). --spec delete_user(ctx:ctx(), binary(), maps:map()) -> ok | {error, integer()}. -delete_user(Ctx, Username, _Optional) -> +-spec delete_user(ctx:ctx(), binary(), maps:map()) -> {ok, [], petstore_utils:response_info()} | {ok, hackney:client_ref()} | {error, term(), petstore_utils:response_info()}. +delete_user(Ctx, Username, Optional) -> + _OptionalParams = maps:get(params, Optional, #{}), + Method = delete, Path = ["/user/", Username, ""], QS = [], Headers = [], Body1 = [], - Opts = [], + Opts = maps:get(hackney_opts, Optional, []), petstore_utils:request(Ctx, Method, [?BASE_URL, Path], QS, Headers, Body1, Opts). %% @doc Get user by user name --spec get_user_by_name(ctx:ctx(), binary()) -> {ok, list(), petstore_user:petstore_user()} | {error, string()}. +-spec get_user_by_name(ctx:ctx(), binary()) -> {ok, petstore_user:petstore_user(), petstore_utils:response_info()} | {ok, hackney:client_ref()} | {error, term(), petstore_utils:response_info()}. get_user_by_name(Ctx, Username) -> get_user_by_name(Ctx, Username, #{}). --spec get_user_by_name(ctx:ctx(), binary(), maps:map()) -> {ok, list(), petstore_user:petstore_user()} | {error, string()}. -get_user_by_name(Ctx, Username, _Optional) -> +-spec get_user_by_name(ctx:ctx(), binary(), maps:map()) -> {ok, petstore_user:petstore_user(), petstore_utils:response_info()} | {ok, hackney:client_ref()} | {error, term(), petstore_utils:response_info()}. +get_user_by_name(Ctx, Username, Optional) -> + _OptionalParams = maps:get(params, Optional, #{}), + Method = get, Path = ["/user/", Username, ""], QS = [], Headers = [], Body1 = [], - Opts = [], + Opts = maps:get(hackney_opts, Optional, []), petstore_utils:request(Ctx, Method, [?BASE_URL, Path], QS, Headers, Body1, Opts). %% @doc Logs user into the system --spec login_user(ctx:ctx(), binary(), binary()) -> {ok, list(), binary()} | {error, string()}. +-spec login_user(ctx:ctx(), binary(), binary()) -> {ok, binary(), petstore_utils:response_info()} | {ok, hackney:client_ref()} | {error, term(), petstore_utils:response_info()}. login_user(Ctx, Username, Password) -> login_user(Ctx, Username, Password, #{}). --spec login_user(ctx:ctx(), binary(), binary(), maps:map()) -> {ok, list(), binary()} | {error, string()}. -login_user(Ctx, Username, Password, _Optional) -> +-spec login_user(ctx:ctx(), binary(), binary(), maps:map()) -> {ok, binary(), petstore_utils:response_info()} | {ok, hackney:client_ref()} | {error, term(), petstore_utils:response_info()}. +login_user(Ctx, Username, Password, Optional) -> + _OptionalParams = maps:get(params, Optional, #{}), + Method = get, Path = ["/user/login"], - QS = lists:flatten([{<<"username">>, Username}, {<<"password">>, Password}])++[{X, maps:get(X, _Optional)} || X <- [], maps:is_key(X, _Optional)], + QS = lists:flatten([{<<"username">>, Username}, {<<"password">>, Password}])++petstore_utils:optional_params([], _OptionalParams), Headers = [], Body1 = [], - Opts = [], + Opts = maps:get(hackney_opts, Optional, []), petstore_utils:request(Ctx, Method, [?BASE_URL, Path], QS, Headers, Body1, Opts). %% @doc Logs out current logged in user session --spec logout_user(ctx:ctx()) -> ok | {error, integer()}. +-spec logout_user(ctx:ctx()) -> {ok, [], petstore_utils:response_info()} | {ok, hackney:client_ref()} | {error, term(), petstore_utils:response_info()}. logout_user(Ctx) -> logout_user(Ctx, #{}). --spec logout_user(ctx:ctx(), maps:map()) -> ok | {error, integer()}. -logout_user(Ctx, _Optional) -> +-spec logout_user(ctx:ctx(), maps:map()) -> {ok, [], petstore_utils:response_info()} | {ok, hackney:client_ref()} | {error, term(), petstore_utils:response_info()}. +logout_user(Ctx, Optional) -> + _OptionalParams = maps:get(params, Optional, #{}), + Method = get, Path = ["/user/logout"], QS = [], Headers = [], Body1 = [], - Opts = [], + Opts = maps:get(hackney_opts, Optional, []), petstore_utils:request(Ctx, Method, [?BASE_URL, Path], QS, Headers, Body1, Opts). %% @doc Updated user %% This can only be done by the logged in user. --spec update_user(ctx:ctx(), binary(), petstore_user:petstore_user()) -> ok | {error, integer()}. +-spec update_user(ctx:ctx(), binary(), petstore_user:petstore_user()) -> {ok, [], petstore_utils:response_info()} | {ok, hackney:client_ref()} | {error, term(), petstore_utils:response_info()}. update_user(Ctx, Username, Body) -> update_user(Ctx, Username, Body, #{}). --spec update_user(ctx:ctx(), binary(), petstore_user:petstore_user(), maps:map()) -> ok | {error, integer()}. -update_user(Ctx, Username, Body, _Optional) -> +-spec update_user(ctx:ctx(), binary(), petstore_user:petstore_user(), maps:map()) -> {ok, [], petstore_utils:response_info()} | {ok, hackney:client_ref()} | {error, term(), petstore_utils:response_info()}. +update_user(Ctx, Username, Body, Optional) -> + _OptionalParams = maps:get(params, Optional, #{}), + Method = put, Path = ["/user/", Username, ""], QS = [], Headers = [], Body1 = Body, - Opts = [], + Opts = maps:get(hackney_opts, Optional, []), petstore_utils:request(Ctx, Method, [?BASE_URL, Path], QS, Headers, Body1, Opts). diff --git a/samples/client/petstore/erlang-client/src/petstore_utils.erl b/samples/client/petstore/erlang-client/src/petstore_utils.erl index 32dc14b8e1d..823f6ec0d92 100644 --- a/samples/client/petstore/erlang-client/src/petstore_utils.erl +++ b/samples/client/petstore/erlang-client/src/petstore_utils.erl @@ -1,6 +1,11 @@ -module(petstore_utils). --export([request/7]). +-export([request/7, + optional_params/2]). + +-type response_info() :: #{status := integer(), + headers := list()}. +-export_type([response_info/0]). request(_Ctx, Method, Path, QS, Headers, Body, Opts) -> Url = hackney_url:make_url(application:get_env(petstore, host, "localhost"), Path, QS), @@ -13,6 +18,9 @@ request(_Ctx, Method, Path, QS, Headers, Body, Opts) -> end, case hackney:request(Method, Url, Headers, Body1, Opts) 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), @@ -34,3 +42,7 @@ decode_response(Headers, Body) -> _ -> Body end. + +optional_params([], _Params) -> []; +optional_params(Keys, Params) -> + [{Key, maps:get(Key, Params)} || Key <- Keys, maps:is_key(Key, Params)]. From 96c977a16dfd996d5267f1dc079da394d8d945ff Mon Sep 17 00:00:00 2001 From: Tristan Sloughter Date: Tue, 2 Jan 2018 10:04:28 -0800 Subject: [PATCH 4/5] [erlang-client] update auth handling --- .../main/resources/erlang-client/api.mustache | 4 +- .../resources/erlang-client/utils.mustache | 58 ++++++++++++++++-- .../erlang-client/src/petstore_pet_api.erl | 34 ++++++++--- .../erlang-client/src/petstore_store_api.erl | 18 ++++-- .../erlang-client/src/petstore_user_api.erl | 34 ++++++++--- .../erlang-client/src/petstore_utils.erl | 59 +++++++++++++++++-- 6 files changed, 172 insertions(+), 35 deletions(-) diff --git a/modules/swagger-codegen/src/main/resources/erlang-client/api.mustache b/modules/swagger-codegen/src/main/resources/erlang-client/api.mustache index d91c838f125..c292cf28aa3 100644 --- a/modules/swagger-codegen/src/main/resources/erlang-client/api.mustache +++ b/modules/swagger-codegen/src/main/resources/erlang-client/api.mustache @@ -18,15 +18,17 @@ -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, #{})), Method = {{httpMethod}}, Path = ["{{{replacedPathName}}}"], 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, Headers, Body1, Opts). + {{packageName}}_utils:request(Ctx, Method, [?BASE_URL, Path], QS, ContentTypeHeader++Headers, Body1, Opts, Cfg). {{/operation}} diff --git a/modules/swagger-codegen/src/main/resources/erlang-client/utils.mustache b/modules/swagger-codegen/src/main/resources/erlang-client/utils.mustache index 2f2f100b71e..0e47a5788e5 100644 --- a/modules/swagger-codegen/src/main/resources/erlang-client/utils.mustache +++ b/modules/swagger-codegen/src/main/resources/erlang-client/utils.mustache @@ -1,23 +1,27 @@ -module({{packageName}}_utils). --export([request/7, +-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) -> - Url = hackney_url:make_url(application:get_env({{packageName}}, host, "localhost"), Path, QS), +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), - Body1 = case lists:keyfind(<<"Content-Type">>, 1, Headers) of + 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, Headers, Body1, Opts) of + case hackney:request(Method, Url, Headers1, Body1, Opts++ConfigHackneyOpts) of {ok, ClientRef} -> %% return value if Opts includes `async` {ok, ClientRef}; @@ -45,4 +49,46 @@ decode_response(Headers, Body) -> optional_params([], _Params) -> []; optional_params(Keys, Params) -> - [{Key, maps:get(Key, Params)} || Key <- Keys, maps:is_key(Key, Params)]. \ No newline at end of file + [{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 -> + <> + 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). diff --git a/samples/client/petstore/erlang-client/src/petstore_pet_api.erl b/samples/client/petstore/erlang-client/src/petstore_pet_api.erl index d09a3748cf1..88e9829da62 100644 --- a/samples/client/petstore/erlang-client/src/petstore_pet_api.erl +++ b/samples/client/petstore/erlang-client/src/petstore_pet_api.erl @@ -9,7 +9,7 @@ update_pet_with_form/2, update_pet_with_form/3, upload_file/2, upload_file/3]). --define(BASE_URL, <<"/v2">>). +-define(BASE_URL, "/v2"). %% @doc Add a new pet to the store -spec add_pet(ctx:ctx(), petstore_pet:petstore_pet()) -> {ok, [], petstore_utils:response_info()} | {ok, hackney:client_ref()} | {error, term(), petstore_utils:response_info()}. @@ -19,15 +19,17 @@ add_pet(Ctx, Body) -> -spec add_pet(ctx:ctx(), petstore_pet:petstore_pet(), maps:map()) -> {ok, [], petstore_utils:response_info()} | {ok, hackney:client_ref()} | {error, term(), petstore_utils:response_info()}. add_pet(Ctx, Body, Optional) -> _OptionalParams = maps:get(params, Optional, #{}), + Cfg = maps:get(cfg, Optional, application:get_env(kuberl, config, #{})), Method = post, Path = ["/pet"], QS = [], Headers = [], Body1 = Body, + ContentTypeHeader = petstore_utils:select_header_content_type([<<"application/json">>, <<"application/xml">>]), Opts = maps:get(hackney_opts, Optional, []), - petstore_utils:request(Ctx, Method, [?BASE_URL, Path], QS, Headers, Body1, Opts). + petstore_utils:request(Ctx, Method, [?BASE_URL, Path], QS, ContentTypeHeader++Headers, Body1, Opts, Cfg). %% @doc Deletes a pet -spec delete_pet(ctx:ctx(), integer()) -> {ok, [], petstore_utils:response_info()} | {ok, hackney:client_ref()} | {error, term(), petstore_utils:response_info()}. @@ -37,15 +39,17 @@ delete_pet(Ctx, PetId) -> -spec delete_pet(ctx:ctx(), integer(), maps:map()) -> {ok, [], petstore_utils:response_info()} | {ok, hackney:client_ref()} | {error, term(), petstore_utils:response_info()}. delete_pet(Ctx, PetId, Optional) -> _OptionalParams = maps:get(params, Optional, #{}), + Cfg = maps:get(cfg, Optional, application:get_env(kuberl, config, #{})), Method = delete, Path = ["/pet/", PetId, ""], QS = [], Headers = []++petstore_utils:optional_params(['api_key'], _OptionalParams), Body1 = [], + ContentTypeHeader = petstore_utils:select_header_content_type([]), Opts = maps:get(hackney_opts, Optional, []), - petstore_utils:request(Ctx, Method, [?BASE_URL, Path], QS, Headers, Body1, Opts). + petstore_utils:request(Ctx, Method, [?BASE_URL, Path], QS, ContentTypeHeader++Headers, Body1, Opts, Cfg). %% @doc Finds Pets by status %% Multiple status values can be provided with comma separated strings @@ -56,15 +60,17 @@ find_pets_by_status(Ctx, Status) -> -spec find_pets_by_status(ctx:ctx(), list(), maps:map()) -> {ok, [petstore_pet:petstore_pet()], petstore_utils:response_info()} | {ok, hackney:client_ref()} | {error, term(), petstore_utils:response_info()}. find_pets_by_status(Ctx, Status, Optional) -> _OptionalParams = maps:get(params, Optional, #{}), + Cfg = maps:get(cfg, Optional, application:get_env(kuberl, config, #{})), Method = get, Path = ["/pet/findByStatus"], QS = lists:flatten([[{<<"status">>, X} || X <- Status]])++petstore_utils:optional_params([], _OptionalParams), Headers = [], Body1 = [], + ContentTypeHeader = petstore_utils:select_header_content_type([]), Opts = maps:get(hackney_opts, Optional, []), - petstore_utils:request(Ctx, Method, [?BASE_URL, Path], QS, Headers, Body1, Opts). + petstore_utils:request(Ctx, Method, [?BASE_URL, Path], QS, ContentTypeHeader++Headers, Body1, Opts, Cfg). %% @doc Finds Pets by tags %% Multiple tags can be provided with comma separated strings. Use tag1, tag2, tag3 for testing. @@ -75,15 +81,17 @@ find_pets_by_tags(Ctx, Tags) -> -spec find_pets_by_tags(ctx:ctx(), list(), maps:map()) -> {ok, [petstore_pet:petstore_pet()], petstore_utils:response_info()} | {ok, hackney:client_ref()} | {error, term(), petstore_utils:response_info()}. find_pets_by_tags(Ctx, Tags, Optional) -> _OptionalParams = maps:get(params, Optional, #{}), + Cfg = maps:get(cfg, Optional, application:get_env(kuberl, config, #{})), Method = get, Path = ["/pet/findByTags"], QS = lists:flatten([[{<<"tags">>, X} || X <- Tags]])++petstore_utils:optional_params([], _OptionalParams), Headers = [], Body1 = [], + ContentTypeHeader = petstore_utils:select_header_content_type([]), Opts = maps:get(hackney_opts, Optional, []), - petstore_utils:request(Ctx, Method, [?BASE_URL, Path], QS, Headers, Body1, Opts). + petstore_utils:request(Ctx, Method, [?BASE_URL, Path], QS, ContentTypeHeader++Headers, Body1, Opts, Cfg). %% @doc Find pet by ID %% Returns a single pet @@ -94,15 +102,17 @@ get_pet_by_id(Ctx, PetId) -> -spec get_pet_by_id(ctx:ctx(), integer(), maps:map()) -> {ok, petstore_pet:petstore_pet(), petstore_utils:response_info()} | {ok, hackney:client_ref()} | {error, term(), petstore_utils:response_info()}. get_pet_by_id(Ctx, PetId, Optional) -> _OptionalParams = maps:get(params, Optional, #{}), + Cfg = maps:get(cfg, Optional, application:get_env(kuberl, config, #{})), Method = get, Path = ["/pet/", PetId, ""], QS = [], Headers = [], Body1 = [], + ContentTypeHeader = petstore_utils:select_header_content_type([]), Opts = maps:get(hackney_opts, Optional, []), - petstore_utils:request(Ctx, Method, [?BASE_URL, Path], QS, Headers, Body1, Opts). + petstore_utils:request(Ctx, Method, [?BASE_URL, Path], QS, ContentTypeHeader++Headers, Body1, Opts, Cfg). %% @doc Update an existing pet -spec update_pet(ctx:ctx(), petstore_pet:petstore_pet()) -> {ok, [], petstore_utils:response_info()} | {ok, hackney:client_ref()} | {error, term(), petstore_utils:response_info()}. @@ -112,15 +122,17 @@ update_pet(Ctx, Body) -> -spec update_pet(ctx:ctx(), petstore_pet:petstore_pet(), maps:map()) -> {ok, [], petstore_utils:response_info()} | {ok, hackney:client_ref()} | {error, term(), petstore_utils:response_info()}. update_pet(Ctx, Body, Optional) -> _OptionalParams = maps:get(params, Optional, #{}), + Cfg = maps:get(cfg, Optional, application:get_env(kuberl, config, #{})), Method = put, Path = ["/pet"], QS = [], Headers = [], Body1 = Body, + ContentTypeHeader = petstore_utils:select_header_content_type([<<"application/json">>, <<"application/xml">>]), Opts = maps:get(hackney_opts, Optional, []), - petstore_utils:request(Ctx, Method, [?BASE_URL, Path], QS, Headers, Body1, Opts). + petstore_utils:request(Ctx, Method, [?BASE_URL, Path], QS, ContentTypeHeader++Headers, Body1, Opts, Cfg). %% @doc Updates a pet in the store with form data -spec update_pet_with_form(ctx:ctx(), integer()) -> {ok, [], petstore_utils:response_info()} | {ok, hackney:client_ref()} | {error, term(), petstore_utils:response_info()}. @@ -130,15 +142,17 @@ update_pet_with_form(Ctx, PetId) -> -spec update_pet_with_form(ctx:ctx(), integer(), maps:map()) -> {ok, [], petstore_utils:response_info()} | {ok, hackney:client_ref()} | {error, term(), petstore_utils:response_info()}. update_pet_with_form(Ctx, PetId, Optional) -> _OptionalParams = maps:get(params, Optional, #{}), + Cfg = maps:get(cfg, Optional, application:get_env(kuberl, config, #{})), Method = post, Path = ["/pet/", PetId, ""], QS = [], Headers = [], Body1 = {form, []++petstore_utils:optional_params(['name', 'status'], _OptionalParams)}, + ContentTypeHeader = petstore_utils:select_header_content_type([<<"application/x-www-form-urlencoded">>]), Opts = maps:get(hackney_opts, Optional, []), - petstore_utils:request(Ctx, Method, [?BASE_URL, Path], QS, Headers, Body1, Opts). + petstore_utils:request(Ctx, Method, [?BASE_URL, Path], QS, ContentTypeHeader++Headers, Body1, Opts, Cfg). %% @doc uploads an image -spec upload_file(ctx:ctx(), integer()) -> {ok, petstore_api_response:petstore_api_response(), petstore_utils:response_info()} | {ok, hackney:client_ref()} | {error, term(), petstore_utils:response_info()}. @@ -148,14 +162,16 @@ upload_file(Ctx, PetId) -> -spec upload_file(ctx:ctx(), integer(), maps:map()) -> {ok, petstore_api_response:petstore_api_response(), petstore_utils:response_info()} | {ok, hackney:client_ref()} | {error, term(), petstore_utils:response_info()}. upload_file(Ctx, PetId, Optional) -> _OptionalParams = maps:get(params, Optional, #{}), + Cfg = maps:get(cfg, Optional, application:get_env(kuberl, config, #{})), Method = post, Path = ["/pet/", PetId, "/uploadImage"], QS = [], Headers = [], Body1 = {form, []++petstore_utils:optional_params(['additionalMetadata', 'file'], _OptionalParams)}, + ContentTypeHeader = petstore_utils:select_header_content_type([<<"multipart/form-data">>]), Opts = maps:get(hackney_opts, Optional, []), - petstore_utils:request(Ctx, Method, [?BASE_URL, Path], QS, Headers, Body1, Opts). + petstore_utils:request(Ctx, Method, [?BASE_URL, Path], QS, ContentTypeHeader++Headers, Body1, Opts, Cfg). diff --git a/samples/client/petstore/erlang-client/src/petstore_store_api.erl b/samples/client/petstore/erlang-client/src/petstore_store_api.erl index c752632a073..edb764f1d94 100644 --- a/samples/client/petstore/erlang-client/src/petstore_store_api.erl +++ b/samples/client/petstore/erlang-client/src/petstore_store_api.erl @@ -5,7 +5,7 @@ get_order_by_id/2, get_order_by_id/3, place_order/2, place_order/3]). --define(BASE_URL, <<"/v2">>). +-define(BASE_URL, "/v2"). %% @doc Delete purchase order by ID %% For valid response try integer IDs with value < 1000. Anything above 1000 or nonintegers will generate API errors @@ -16,15 +16,17 @@ delete_order(Ctx, OrderId) -> -spec delete_order(ctx:ctx(), binary(), maps:map()) -> {ok, [], petstore_utils:response_info()} | {ok, hackney:client_ref()} | {error, term(), petstore_utils:response_info()}. delete_order(Ctx, OrderId, Optional) -> _OptionalParams = maps:get(params, Optional, #{}), + Cfg = maps:get(cfg, Optional, application:get_env(kuberl, config, #{})), Method = delete, Path = ["/store/order/", OrderId, ""], QS = [], Headers = [], Body1 = [], + ContentTypeHeader = petstore_utils:select_header_content_type([]), Opts = maps:get(hackney_opts, Optional, []), - petstore_utils:request(Ctx, Method, [?BASE_URL, Path], QS, Headers, Body1, Opts). + petstore_utils:request(Ctx, Method, [?BASE_URL, Path], QS, ContentTypeHeader++Headers, Body1, Opts, Cfg). %% @doc Returns pet inventories by status %% Returns a map of status codes to quantities @@ -35,15 +37,17 @@ get_inventory(Ctx) -> -spec get_inventory(ctx:ctx(), maps:map()) -> {ok, maps:map(), petstore_utils:response_info()} | {ok, hackney:client_ref()} | {error, term(), petstore_utils:response_info()}. get_inventory(Ctx, Optional) -> _OptionalParams = maps:get(params, Optional, #{}), + Cfg = maps:get(cfg, Optional, application:get_env(kuberl, config, #{})), Method = get, Path = ["/store/inventory"], QS = [], Headers = [], Body1 = [], + ContentTypeHeader = petstore_utils:select_header_content_type([]), Opts = maps:get(hackney_opts, Optional, []), - petstore_utils:request(Ctx, Method, [?BASE_URL, Path], QS, Headers, Body1, Opts). + petstore_utils:request(Ctx, Method, [?BASE_URL, Path], QS, ContentTypeHeader++Headers, Body1, Opts, Cfg). %% @doc Find purchase order by ID %% For valid response try integer IDs with value <= 5 or > 10. Other values will generated exceptions @@ -54,15 +58,17 @@ get_order_by_id(Ctx, OrderId) -> -spec get_order_by_id(ctx:ctx(), integer(), maps:map()) -> {ok, petstore_order:petstore_order(), petstore_utils:response_info()} | {ok, hackney:client_ref()} | {error, term(), petstore_utils:response_info()}. get_order_by_id(Ctx, OrderId, Optional) -> _OptionalParams = maps:get(params, Optional, #{}), + Cfg = maps:get(cfg, Optional, application:get_env(kuberl, config, #{})), Method = get, Path = ["/store/order/", OrderId, ""], QS = [], Headers = [], Body1 = [], + ContentTypeHeader = petstore_utils:select_header_content_type([]), Opts = maps:get(hackney_opts, Optional, []), - petstore_utils:request(Ctx, Method, [?BASE_URL, Path], QS, Headers, Body1, Opts). + petstore_utils:request(Ctx, Method, [?BASE_URL, Path], QS, ContentTypeHeader++Headers, Body1, Opts, Cfg). %% @doc Place an order for a pet -spec place_order(ctx:ctx(), petstore_order:petstore_order()) -> {ok, petstore_order:petstore_order(), petstore_utils:response_info()} | {ok, hackney:client_ref()} | {error, term(), petstore_utils:response_info()}. @@ -72,14 +78,16 @@ place_order(Ctx, Body) -> -spec place_order(ctx:ctx(), petstore_order:petstore_order(), maps:map()) -> {ok, petstore_order:petstore_order(), petstore_utils:response_info()} | {ok, hackney:client_ref()} | {error, term(), petstore_utils:response_info()}. place_order(Ctx, Body, Optional) -> _OptionalParams = maps:get(params, Optional, #{}), + Cfg = maps:get(cfg, Optional, application:get_env(kuberl, config, #{})), Method = post, Path = ["/store/order"], QS = [], Headers = [], Body1 = Body, + ContentTypeHeader = petstore_utils:select_header_content_type([]), Opts = maps:get(hackney_opts, Optional, []), - petstore_utils:request(Ctx, Method, [?BASE_URL, Path], QS, Headers, Body1, Opts). + petstore_utils:request(Ctx, Method, [?BASE_URL, Path], QS, ContentTypeHeader++Headers, Body1, Opts, Cfg). diff --git a/samples/client/petstore/erlang-client/src/petstore_user_api.erl b/samples/client/petstore/erlang-client/src/petstore_user_api.erl index 5405c236ff2..d6b95213fbf 100644 --- a/samples/client/petstore/erlang-client/src/petstore_user_api.erl +++ b/samples/client/petstore/erlang-client/src/petstore_user_api.erl @@ -9,7 +9,7 @@ logout_user/1, logout_user/2, update_user/3, update_user/4]). --define(BASE_URL, <<"/v2">>). +-define(BASE_URL, "/v2"). %% @doc Create user %% This can only be done by the logged in user. @@ -20,15 +20,17 @@ create_user(Ctx, Body) -> -spec create_user(ctx:ctx(), petstore_user:petstore_user(), maps:map()) -> {ok, [], petstore_utils:response_info()} | {ok, hackney:client_ref()} | {error, term(), petstore_utils:response_info()}. create_user(Ctx, Body, Optional) -> _OptionalParams = maps:get(params, Optional, #{}), + Cfg = maps:get(cfg, Optional, application:get_env(kuberl, config, #{})), Method = post, Path = ["/user"], QS = [], Headers = [], Body1 = Body, + ContentTypeHeader = petstore_utils:select_header_content_type([]), Opts = maps:get(hackney_opts, Optional, []), - petstore_utils:request(Ctx, Method, [?BASE_URL, Path], QS, Headers, Body1, Opts). + petstore_utils:request(Ctx, Method, [?BASE_URL, Path], QS, ContentTypeHeader++Headers, Body1, Opts, Cfg). %% @doc Creates list of users with given input array -spec create_users_with_array_input(ctx:ctx(), list()) -> {ok, [], petstore_utils:response_info()} | {ok, hackney:client_ref()} | {error, term(), petstore_utils:response_info()}. @@ -38,15 +40,17 @@ create_users_with_array_input(Ctx, Body) -> -spec create_users_with_array_input(ctx:ctx(), list(), maps:map()) -> {ok, [], petstore_utils:response_info()} | {ok, hackney:client_ref()} | {error, term(), petstore_utils:response_info()}. create_users_with_array_input(Ctx, Body, Optional) -> _OptionalParams = maps:get(params, Optional, #{}), + Cfg = maps:get(cfg, Optional, application:get_env(kuberl, config, #{})), Method = post, Path = ["/user/createWithArray"], QS = [], Headers = [], Body1 = Body, + ContentTypeHeader = petstore_utils:select_header_content_type([]), Opts = maps:get(hackney_opts, Optional, []), - petstore_utils:request(Ctx, Method, [?BASE_URL, Path], QS, Headers, Body1, Opts). + petstore_utils:request(Ctx, Method, [?BASE_URL, Path], QS, ContentTypeHeader++Headers, Body1, Opts, Cfg). %% @doc Creates list of users with given input array -spec create_users_with_list_input(ctx:ctx(), list()) -> {ok, [], petstore_utils:response_info()} | {ok, hackney:client_ref()} | {error, term(), petstore_utils:response_info()}. @@ -56,15 +60,17 @@ create_users_with_list_input(Ctx, Body) -> -spec create_users_with_list_input(ctx:ctx(), list(), maps:map()) -> {ok, [], petstore_utils:response_info()} | {ok, hackney:client_ref()} | {error, term(), petstore_utils:response_info()}. create_users_with_list_input(Ctx, Body, Optional) -> _OptionalParams = maps:get(params, Optional, #{}), + Cfg = maps:get(cfg, Optional, application:get_env(kuberl, config, #{})), Method = post, Path = ["/user/createWithList"], QS = [], Headers = [], Body1 = Body, + ContentTypeHeader = petstore_utils:select_header_content_type([]), Opts = maps:get(hackney_opts, Optional, []), - petstore_utils:request(Ctx, Method, [?BASE_URL, Path], QS, Headers, Body1, Opts). + petstore_utils:request(Ctx, Method, [?BASE_URL, Path], QS, ContentTypeHeader++Headers, Body1, Opts, Cfg). %% @doc Delete user %% This can only be done by the logged in user. @@ -75,15 +81,17 @@ delete_user(Ctx, Username) -> -spec delete_user(ctx:ctx(), binary(), maps:map()) -> {ok, [], petstore_utils:response_info()} | {ok, hackney:client_ref()} | {error, term(), petstore_utils:response_info()}. delete_user(Ctx, Username, Optional) -> _OptionalParams = maps:get(params, Optional, #{}), + Cfg = maps:get(cfg, Optional, application:get_env(kuberl, config, #{})), Method = delete, Path = ["/user/", Username, ""], QS = [], Headers = [], Body1 = [], + ContentTypeHeader = petstore_utils:select_header_content_type([]), Opts = maps:get(hackney_opts, Optional, []), - petstore_utils:request(Ctx, Method, [?BASE_URL, Path], QS, Headers, Body1, Opts). + petstore_utils:request(Ctx, Method, [?BASE_URL, Path], QS, ContentTypeHeader++Headers, Body1, Opts, Cfg). %% @doc Get user by user name -spec get_user_by_name(ctx:ctx(), binary()) -> {ok, petstore_user:petstore_user(), petstore_utils:response_info()} | {ok, hackney:client_ref()} | {error, term(), petstore_utils:response_info()}. @@ -93,15 +101,17 @@ get_user_by_name(Ctx, Username) -> -spec get_user_by_name(ctx:ctx(), binary(), maps:map()) -> {ok, petstore_user:petstore_user(), petstore_utils:response_info()} | {ok, hackney:client_ref()} | {error, term(), petstore_utils:response_info()}. get_user_by_name(Ctx, Username, Optional) -> _OptionalParams = maps:get(params, Optional, #{}), + Cfg = maps:get(cfg, Optional, application:get_env(kuberl, config, #{})), Method = get, Path = ["/user/", Username, ""], QS = [], Headers = [], Body1 = [], + ContentTypeHeader = petstore_utils:select_header_content_type([]), Opts = maps:get(hackney_opts, Optional, []), - petstore_utils:request(Ctx, Method, [?BASE_URL, Path], QS, Headers, Body1, Opts). + petstore_utils:request(Ctx, Method, [?BASE_URL, Path], QS, ContentTypeHeader++Headers, Body1, Opts, Cfg). %% @doc Logs user into the system -spec login_user(ctx:ctx(), binary(), binary()) -> {ok, binary(), petstore_utils:response_info()} | {ok, hackney:client_ref()} | {error, term(), petstore_utils:response_info()}. @@ -111,15 +121,17 @@ login_user(Ctx, Username, Password) -> -spec login_user(ctx:ctx(), binary(), binary(), maps:map()) -> {ok, binary(), petstore_utils:response_info()} | {ok, hackney:client_ref()} | {error, term(), petstore_utils:response_info()}. login_user(Ctx, Username, Password, Optional) -> _OptionalParams = maps:get(params, Optional, #{}), + Cfg = maps:get(cfg, Optional, application:get_env(kuberl, config, #{})), Method = get, Path = ["/user/login"], QS = lists:flatten([{<<"username">>, Username}, {<<"password">>, Password}])++petstore_utils:optional_params([], _OptionalParams), Headers = [], Body1 = [], + ContentTypeHeader = petstore_utils:select_header_content_type([]), Opts = maps:get(hackney_opts, Optional, []), - petstore_utils:request(Ctx, Method, [?BASE_URL, Path], QS, Headers, Body1, Opts). + petstore_utils:request(Ctx, Method, [?BASE_URL, Path], QS, ContentTypeHeader++Headers, Body1, Opts, Cfg). %% @doc Logs out current logged in user session -spec logout_user(ctx:ctx()) -> {ok, [], petstore_utils:response_info()} | {ok, hackney:client_ref()} | {error, term(), petstore_utils:response_info()}. @@ -129,15 +141,17 @@ logout_user(Ctx) -> -spec logout_user(ctx:ctx(), maps:map()) -> {ok, [], petstore_utils:response_info()} | {ok, hackney:client_ref()} | {error, term(), petstore_utils:response_info()}. logout_user(Ctx, Optional) -> _OptionalParams = maps:get(params, Optional, #{}), + Cfg = maps:get(cfg, Optional, application:get_env(kuberl, config, #{})), Method = get, Path = ["/user/logout"], QS = [], Headers = [], Body1 = [], + ContentTypeHeader = petstore_utils:select_header_content_type([]), Opts = maps:get(hackney_opts, Optional, []), - petstore_utils:request(Ctx, Method, [?BASE_URL, Path], QS, Headers, Body1, Opts). + petstore_utils:request(Ctx, Method, [?BASE_URL, Path], QS, ContentTypeHeader++Headers, Body1, Opts, Cfg). %% @doc Updated user %% This can only be done by the logged in user. @@ -148,14 +162,16 @@ update_user(Ctx, Username, Body) -> -spec update_user(ctx:ctx(), binary(), petstore_user:petstore_user(), maps:map()) -> {ok, [], petstore_utils:response_info()} | {ok, hackney:client_ref()} | {error, term(), petstore_utils:response_info()}. update_user(Ctx, Username, Body, Optional) -> _OptionalParams = maps:get(params, Optional, #{}), + Cfg = maps:get(cfg, Optional, application:get_env(kuberl, config, #{})), Method = put, Path = ["/user/", Username, ""], QS = [], Headers = [], Body1 = Body, + ContentTypeHeader = petstore_utils:select_header_content_type([]), Opts = maps:get(hackney_opts, Optional, []), - petstore_utils:request(Ctx, Method, [?BASE_URL, Path], QS, Headers, Body1, Opts). + petstore_utils:request(Ctx, Method, [?BASE_URL, Path], QS, ContentTypeHeader++Headers, Body1, Opts, Cfg). diff --git a/samples/client/petstore/erlang-client/src/petstore_utils.erl b/samples/client/petstore/erlang-client/src/petstore_utils.erl index 823f6ec0d92..1d5e515f62d 100644 --- a/samples/client/petstore/erlang-client/src/petstore_utils.erl +++ b/samples/client/petstore/erlang-client/src/petstore_utils.erl @@ -1,23 +1,27 @@ -module(petstore_utils). --export([request/7, +-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) -> - Url = hackney_url:make_url(application:get_env(petstore, host, "localhost"), Path, QS), +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), - Body1 = case lists:keyfind(<<"Content-Type">>, 1, Headers) of + 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, Headers, Body1, Opts) of + case hackney:request(Method, Url, Headers1, Body1, Opts++ConfigHackneyOpts) of {ok, ClientRef} -> %% return value if Opts includes `async` {ok, ClientRef}; @@ -46,3 +50,48 @@ decode_response(Headers, Body) -> 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 -> + <> + end. + +update_params_with_auth(Cfg, Headers, QS) -> + AuthSettings = maps:get(auth, Cfg, #{}), + Auths = #{ 'api_key' => + #{type => 'apiKey', + key => <<"api_key">>, + in => header}, 'petstore_auth' => + #{type => 'oauth2', + key => <<"">>, + in => }}, + + 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). From 11292fdf67220d2abee4d10493c73c21fce3bcee Mon Sep 17 00:00:00 2001 From: Tristan Sloughter Date: Sat, 20 Jan 2018 09:36:09 -0800 Subject: [PATCH 5/5] [erlang-client] remove underscore2, replacing with original underscore + replaceAll --- .../languages/ErlangClientCodegen.java | 33 +++++-------------- 1 file changed, 8 insertions(+), 25 deletions(-) diff --git a/modules/swagger-codegen/src/main/java/io/swagger/codegen/languages/ErlangClientCodegen.java b/modules/swagger-codegen/src/main/java/io/swagger/codegen/languages/ErlangClientCodegen.java index a7f5e5d0ec6..b3f7fe0d55b 100644 --- a/modules/swagger-codegen/src/main/java/io/swagger/codegen/languages/ErlangClientCodegen.java +++ b/modules/swagger-codegen/src/main/java/io/swagger/codegen/languages/ErlangClientCodegen.java @@ -117,24 +117,6 @@ public String getSwaggerType(Property p) { return type; } - public static String underscore2(String word) { - String firstPattern = "([A-Z]+)([A-Z][a-z])"; - String secondPattern = "([a-z\\d])([A-Z])"; - String replacementPattern = "$1_$2"; - // Replace package separator with slash. - word = word.replaceAll("\\.", "_"); // FIXME: a parameter should not be assigned. Also declare the methods parameters as 'final'. - // Replace $ with two underscores for inner classes. - word = word.replaceAll("\\$", "__"); - // Replace capital letter with _ plus lowercase letter. - word = word.replaceAll(firstPattern, replacementPattern); - word = word.replaceAll(secondPattern, replacementPattern); - word = word.replace('-', '_'); - // replace space with underscore - word = word.replace(' ', '_'); - word = word.toLowerCase(); - return word; - } - @Override public void processOpts() { super.processOpts(); @@ -240,37 +222,38 @@ public String toParamName(String name) { @Override public String toModelName(String name) { - return this.packageName + "_" + underscore2(name.replaceAll("-", "_")); + return this.packageName + "_" + underscore(name.replaceAll("-", "_").replaceAll("\\.", "_")); } @Override public String toApiName(String name) { - return this.packageName + "_" + underscore2(name.replaceAll("-", "_")); + return this.packageName + "_" + underscore(name.replaceAll("-", "_").replaceAll("\\.", "_")); } @Override public String toModelFilename(String name) { - return this.packageName + "_" + underscore2(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 + "_" + underscore2(name) + "_api"; + return this.packageName + "_" + underscore(name) + "_api"; } @Override 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 " + underscore2(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 underscore2(operationId); + return underscore(operationId.replaceAll("\\.", "_")); } @Override