From 771b69d270df888a28fd243926c43bda4239bccc Mon Sep 17 00:00:00 2001 From: Tristan Sloughter Date: Wed, 13 Sep 2017 16:16:25 -0700 Subject: [PATCH 1/8] WIP: initial commit for Erlang client generator --- bin/erlang-petstore-client.sh | 31 ++ .../languages/ErlangClientCodegen.java | 359 ++++++++++++++++++ .../services/io.swagger.codegen.CodegenConfig | 1 + .../resources/erlang-client/README.mustache | 5 + .../main/resources/erlang-client/api.mustache | 25 ++ .../resources/erlang-client/app.src.mustache | 17 + .../resources/erlang-client/model.mustache | 0 .../erlang-client/rebar.config.mustache | 3 + 8 files changed, 441 insertions(+) create mode 100755 bin/erlang-petstore-client.sh create mode 100644 modules/swagger-codegen/src/main/java/io/swagger/codegen/languages/ErlangClientCodegen.java create mode 100644 modules/swagger-codegen/src/main/resources/erlang-client/README.mustache create mode 100644 modules/swagger-codegen/src/main/resources/erlang-client/api.mustache create mode 100644 modules/swagger-codegen/src/main/resources/erlang-client/app.src.mustache create mode 100644 modules/swagger-codegen/src/main/resources/erlang-client/model.mustache create mode 100644 modules/swagger-codegen/src/main/resources/erlang-client/rebar.config.mustache diff --git a/bin/erlang-petstore-client.sh b/bin/erlang-petstore-client.sh new file mode 100755 index 00000000000..686ecd25629 --- /dev/null +++ b/bin/erlang-petstore-client.sh @@ -0,0 +1,31 @@ +#!/bin/sh + +SCRIPT="$0" + +while [ -h "$SCRIPT" ] ; do + ls=`ls -ld "$SCRIPT"` + link=`expr "$ls" : '.*-> \(.*\)$'` + if expr "$link" : '/.*' > /dev/null; then + SCRIPT="$link" + else + SCRIPT=`dirname "$SCRIPT"`/"$link" + fi +done + +if [ ! -d "${APP_DIR}" ]; then + APP_DIR=`dirname "$SCRIPT"`/.. + APP_DIR=`cd "${APP_DIR}"; pwd` +fi + +executable="./modules/swagger-codegen-cli/target/swagger-codegen-cli.jar" + +if [ ! -f "$executable" ] +then + mvn clean package +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" + +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 new file mode 100644 index 00000000000..3775961f4cf --- /dev/null +++ b/modules/swagger-codegen/src/main/java/io/swagger/codegen/languages/ErlangClientCodegen.java @@ -0,0 +1,359 @@ +package io.swagger.codegen.languages; + +import io.swagger.codegen.*; +import com.samskivert.mustache.Mustache; +import com.samskivert.mustache.Template; +import io.swagger.models.properties.ArrayProperty; +import io.swagger.models.properties.MapProperty; +import io.swagger.models.properties.Property; +import io.swagger.models.parameters.Parameter; + +import java.io.File; +import java.util.*; +import java.io.Writer; +import java.io.IOException; +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +import org.apache.commons.lang3.StringUtils; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +public class ErlangClientCodegen extends DefaultCodegen implements CodegenConfig { + static Logger LOGGER = LoggerFactory.getLogger(ErlangClientCodegen.class); + + protected String packageName = "swagger"; + protected String packageVersion = "1.0.0"; + protected String sourceFolder = "src"; + + public CodegenType getTag() { + return CodegenType.CLIENT; + } + + public String getName() { + return "erlang-client"; + } + + public String getHelp() { + return "Generates an Erlang client library (beta)."; + } + + public ErlangClientCodegen() { + super(); + outputFolder = "generated-code/erlang"; + //modelTemplateFiles.put("model.mustache", ".erl"); + apiTemplateFiles.put("api.mustache", ".erl"); + + embeddedTemplateDir = templateDir = "erlang-client"; + + setReservedWordsLowerCase( + Arrays.asList( + "after","and","andalso","band","begin","bnot","bor","bsl","bsr","bxor","case", + "catch","cond","div","end","fun","if","let","not","of","or","orelse","receive", + "rem","try","when","xor" + ) + ); + + instantiationTypes.clear(); + + typeMapping.clear(); + typeMapping.put("enum", "binary"); + typeMapping.put("date", "date"); + typeMapping.put("datetime", "datetime"); + typeMapping.put("boolean", "boolean"); + typeMapping.put("string", "binary"); + typeMapping.put("integer", "integer"); + typeMapping.put("int", "integer"); + typeMapping.put("float", "integer"); + typeMapping.put("long", "integer"); + typeMapping.put("double", "float"); + typeMapping.put("array", "list"); + typeMapping.put("map", "map"); + typeMapping.put("number", "integer"); + typeMapping.put("bigdecimal", "float"); + typeMapping.put("List", "list"); + typeMapping.put("object", "object"); + typeMapping.put("file", "file"); + typeMapping.put("binary", "binary"); + typeMapping.put("bytearray", "binary"); + typeMapping.put("byte", "binary"); + typeMapping.put("uuid", "binary"); + typeMapping.put("password", "binary"); + + cliOptions.clear(); + cliOptions.add(new CliOption(CodegenConstants.PACKAGE_NAME, "Erlang application name (convention: lowercase).") + .defaultValue(this.packageName)); + cliOptions.add(new CliOption(CodegenConstants.PACKAGE_NAME, "Erlang application version") + .defaultValue(this.packageVersion)); + + + } + + @Override + public void processOpts() { + super.processOpts(); + + if (additionalProperties.containsKey(CodegenConstants.PACKAGE_NAME)) { + setPackageName((String) additionalProperties.get(CodegenConstants.PACKAGE_NAME)); + } + else { + setPackageName("swagger"); + } + + if (additionalProperties.containsKey(CodegenConstants.PACKAGE_VERSION)) { + setPackageVersion((String) additionalProperties.get(CodegenConstants.PACKAGE_VERSION)); + } + else { + setPackageVersion("1.0.0"); + } + + additionalProperties.put(CodegenConstants.PACKAGE_NAME, packageName); + additionalProperties.put(CodegenConstants.PACKAGE_VERSION, packageVersion); + + additionalProperties.put("lowercase", new Mustache.Lambda() { + @Override + public void execute(Template.Fragment fragment, Writer writer) throws IOException { + writer.write(lowercase(fragment.execute())); + } + }); + + additionalProperties.put("length", new Mustache.Lambda() { + @Override + public void execute(Template.Fragment fragment, Writer writer) throws IOException { + writer.write(length(fragment.context())); + } + }); + + modelPackage = packageName; + apiPackage = packageName; + + 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("README.mustache", "", "README.md")); + } + + @Override + public String escapeReservedWord(String name) + { + // Can't start with an underscore, as our fields need to start with an + // UppercaseLetter so that Go treats them as public/visible. + + // Options? + // - MyName + // - AName + // - TheName + // - XName + // - X_Name + // ... or maybe a suffix? + // - Name_ ... think this will work. + if(this.reservedWordsMappings().containsKey(name)) { + return this.reservedWordsMappings().get(name); + } + return camelize(name) + '_'; + } + + @Override + public String apiFileFolder() { + return outputFolder + File.separator + sourceFolder + File.separator; + } + + + @Override + public String toVarName(String name) { + // replace - with _ e.g. created-at => created_at + name = sanitizeName(name.replaceAll("-", "_")); + + // if it's all uppper case, do nothing + if (name.matches("^[A-Z_]*$")) + return name; + + // camelize (lower first character) the variable name + // pet_id => PetId + name = camelize(name); + + // for reserved word or word starting with number, append _ + if (isReservedWord(name)) + name = escapeReservedWord(name); + + // for reserved word or word starting with number, append _ + if (name.matches("^\\d.*")) + name = "Var" + name; + + return name; + } + + @Override + public String toParamName(String name) { + return camelize(toVarName(name)); + } + + @Override + public String toModelName(String name) { + return this.packageName + "_" + underscore(name.replaceAll("-", "_")); + } + + @Override + public String toApiName(String name) { + return this.packageName + "_" + underscore(name.replaceAll("-", "_")); + } + + @Override + public String toModelFilename(String name) { + return this.packageName + "_" + underscore(name); + } + + @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'. + + // e.g. PetApi.erl => pet_api.erl + 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 " + underscore(sanitizeName("call_" + operationId))); + operationId = "call_" + operationId; + } + + return underscore(operationId); + } + + @Override + public Map postProcessOperations(Map objs) { + Map operations = (Map) objs.get("operations"); + List os = (List) operations.get("operation"); + List newOs = new ArrayList(); + Pattern pattern = Pattern.compile("(.*)\\{([^\\}]+)\\}(.*)"); + for (CodegenOperation o : os) { + ArrayList pathTemplateNames = new ArrayList(); + Matcher matcher = pattern.matcher(o.path); + StringBuffer buffer = new StringBuffer(); + while (matcher.find()) { + String pathTemplateName = matcher.group(2); + matcher.appendReplacement(buffer, "$1" + "\", " + camelize(pathTemplateName) + ", \"" + "$3"); + pathTemplateNames.add(pathTemplateName); + } + ExtendedCodegenOperation eco = new ExtendedCodegenOperation(o); + if (buffer.toString().isEmpty()) { + eco.setReplacedPathName(o.path); + } else { + eco.setReplacedPathName(buffer.toString()); + } + eco.setPathTemplateNames(pathTemplateNames); + newOs.add(eco); + } + operations.put("operation", newOs); + return objs; + } + + public void setPackageName(String packageName) { + this.packageName = packageName; + } + + public void setPackageVersion(String packageVersion) { + this.packageVersion = packageVersion; + } + + String lowercase(String word) { + return word.toLowerCase(); + } + + String length(Object o) { + return Integer.toString((((ExtendedCodegenOperation) o).allParams).size()); + } + + @Override + public String escapeQuotationMark(String input) { + // remove " to avoid code injection + return input.replace("\"", ""); + } + + @Override + public String escapeUnsafeCharacters(String input) { + return input.replace("*/", "*_/").replace("/*", "/_*"); + } + + class ExtendedCodegenOperation extends CodegenOperation { + private List pathTemplateNames = new ArrayList(); + private String replacedPathName; + + public ExtendedCodegenOperation(CodegenOperation o) { + super(); + + // Copy all fields of CodegenOperation + this.responseHeaders.addAll(o.responseHeaders); + this.hasAuthMethods = o.hasAuthMethods; + this.hasConsumes = o.hasConsumes; + this.hasProduces = o.hasProduces; + this.hasParams = o.hasParams; + this.hasOptionalParams = o.hasOptionalParams; + this.returnTypeIsPrimitive = o.returnTypeIsPrimitive; + this.returnSimpleType = o.returnSimpleType; + this.subresourceOperation = o.subresourceOperation; + this.isMapContainer = o.isMapContainer; + this.isListContainer = o.isListContainer; + this.isMultipart = o.isMultipart; + this.hasMore = o.hasMore; + this.isResponseBinary = o.isResponseBinary; + this.hasReference = o.hasReference; + this.isRestfulIndex = o.isRestfulIndex; + this.isRestfulShow = o.isRestfulShow; + this.isRestfulCreate = o.isRestfulCreate; + this.isRestfulUpdate = o.isRestfulUpdate; + this.isRestfulDestroy = o.isRestfulDestroy; + this.isRestful = o.isRestful; + this.path = o.path; + this.operationId = o.operationId; + this.returnType = o.returnType; + this.httpMethod = o.httpMethod; + this.returnBaseType = o.returnBaseType; + this.returnContainer = o.returnContainer; + this.summary = o.summary; + this.unescapedNotes = o.unescapedNotes; + this.notes = o.notes; + this.baseName = o.baseName; + this.defaultResponse = o.defaultResponse; + this.discriminator = o.discriminator; + this.consumes = o.consumes; + this.produces = o.produces; + this.bodyParam = o.bodyParam; + this.allParams = o.allParams; + this.bodyParams = o.bodyParams; + this.pathParams = o.pathParams; + this.queryParams = o.queryParams; + this.headerParams = o.headerParams; + this.formParams = o.formParams; + this.authMethods = o.authMethods; + this.tags = o.tags; + this.responses = o.responses; + this.imports = o.imports; + this.examples = o.examples; + this.externalDocs = o.externalDocs; + this.vendorExtensions = o.vendorExtensions; + this.nickname = o.nickname; + this.operationIdLowerCase = o.operationIdLowerCase; + this.operationIdCamelCase = o.operationIdCamelCase; + } + + public List getPathTemplateNames() { + return pathTemplateNames; + } + + public void setPathTemplateNames(List pathTemplateNames) { + this.pathTemplateNames = pathTemplateNames; + } + + public String getReplacedPathName() { + return replacedPathName; + } + + public void setReplacedPathName(String replacedPathName) { + this.replacedPathName = replacedPathName; + } + } +} diff --git a/modules/swagger-codegen/src/main/resources/META-INF/services/io.swagger.codegen.CodegenConfig b/modules/swagger-codegen/src/main/resources/META-INF/services/io.swagger.codegen.CodegenConfig index c8438e09a30..ae148900400 100644 --- a/modules/swagger-codegen/src/main/resources/META-INF/services/io.swagger.codegen.CodegenConfig +++ b/modules/swagger-codegen/src/main/resources/META-INF/services/io.swagger.codegen.CodegenConfig @@ -13,6 +13,7 @@ io.swagger.codegen.languages.CsharpDotNet2ClientCodegen io.swagger.codegen.languages.DartClientCodegen io.swagger.codegen.languages.ElixirClientCodegen io.swagger.codegen.languages.EiffelClientCodegen +io.swagger.codegen.languages.ErlangClientCodegen io.swagger.codegen.languages.ErlangServerCodegen io.swagger.codegen.languages.FinchServerCodegen io.swagger.codegen.languages.FlashClientCodegen diff --git a/modules/swagger-codegen/src/main/resources/erlang-client/README.mustache b/modules/swagger-codegen/src/main/resources/erlang-client/README.mustache new file mode 100644 index 00000000000..f3eab0b5528 --- /dev/null +++ b/modules/swagger-codegen/src/main/resources/erlang-client/README.mustache @@ -0,0 +1,5 @@ +# Swagger client server library for Erlang + +## Overview + +An Erlang client stub generated by [Swagger Codegen](https://github.com/swagger-api/swagger-codegen) given an OpenAPI/Swagger spec. diff --git a/modules/swagger-codegen/src/main/resources/erlang-client/api.mustache b/modules/swagger-codegen/src/main/resources/erlang-client/api.mustache new file mode 100644 index 00000000000..9aa1e4ac6af --- /dev/null +++ b/modules/swagger-codegen/src/main/resources/erlang-client/api.mustache @@ -0,0 +1,25 @@ +-module({{classname}}_api). + +-export([{{#operations}}{{#operation}}{{^-first}}, + {{/-first}}{{operationId}}/{{#length}}{{allParams}}{{/length}}{{/operation}}{{/operations}}]). + +-define(BASE_URL, <<"{{{basePath}}}">>). + +{{#operations}} + {{#operation}} + +%% {{summary}} +%% {{^notes.isEmpty}} +%% {{notes}} +%% {{/notes.isEmpty}} +{{operationId}}({{#allParams}}{{^-first}}, {{/-first}}{{paramName}}{{/allParams}}) -> + Method = {{#lowercase}}{{httpMethod}}{{/lowercase}}, + Path = ["{{{replacedPathName}}}"], + QS = [{{^queryParams.isEmpty}}{{#queryParams}}{{^-first}}, {{/-first}}{<<"{{baseName}}">>, {{paramName}}}{{/queryParams}}{{/queryParams.isEmpty}}], + Headers = [{{^headerParams.isEmpty}}{{#headerParams}}{{^-first}}, {{/-first}}{<<"{{baseName}}">>, {{paramName}}}{{/headerParams}}{{/headerParams.isEmpty}}], + Body1 = {{^formParams.isEmpty}}{form, [{{#formParams}}{{^-first}}, {{/-first}}{<<"{{baseName}}">>, {{paramName}}}{{/formParams}}]}{{/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), + hackney:request(Method, Url, Headers, Body1, Opts). + {{/operation}} +{{/operations}} 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 new file mode 100644 index 00000000000..8cf0543467a --- /dev/null +++ b/modules/swagger-codegen/src/main/resources/erlang-client/app.src.mustache @@ -0,0 +1,17 @@ +{application, {{packageName}}, + [{description, {{#appDescription}}"{{appDescription}}"{{/appDescription}}{{^appDescription}}"Swagger client library"{{/appDescription}}}, + {vsn, "{{apiVersion}}"}, + {registered, []}, + {applications, + [kernel, + stdlib, + ssl, + hackney + ]}, + {env, []}, + {modules, []}, + + {maintainers, []}, + {licenses, [{{#licenseInfo}}"{{licenseInfo}}"{{/licenseInfo}}]}, + {links, [{{#infoUrl}}"{{infoUrl}}"{{/infoUrl}}]} +]}. diff --git a/modules/swagger-codegen/src/main/resources/erlang-client/model.mustache b/modules/swagger-codegen/src/main/resources/erlang-client/model.mustache new file mode 100644 index 00000000000..e69de29bb2d 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 new file mode 100644 index 00000000000..abe84a1a9f3 --- /dev/null +++ b/modules/swagger-codegen/src/main/resources/erlang-client/rebar.config.mustache @@ -0,0 +1,3 @@ +{erl_opts, [debug_info, warnings_as_errors, warn_untyped_record]}. + +{deps, [jsx, hackney]}. From c0c17bd65de4c0b78919b7e16f0d1a344adadee8 Mon Sep 17 00:00:00 2001 From: Tristan Sloughter Date: Wed, 13 Sep 2017 18:37:48 -0700 Subject: [PATCH 2/8] add models types and function type specs --- .../languages/ErlangClientCodegen.java | 69 +++++++++---------- .../main/resources/erlang-client/api.mustache | 10 +-- .../resources/erlang-client/model.mustache | 12 ++++ 3 files changed, 51 insertions(+), 40 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 3775961f4cf..68ca55eca74 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 @@ -42,7 +42,7 @@ public String getHelp() { public ErlangClientCodegen() { super(); outputFolder = "generated-code/erlang"; - //modelTemplateFiles.put("model.mustache", ".erl"); + modelTemplateFiles.put("model.mustache", ".erl"); apiTemplateFiles.put("api.mustache", ".erl"); embeddedTemplateDir = templateDir = "erlang-client"; @@ -58,28 +58,29 @@ public ErlangClientCodegen() { instantiationTypes.clear(); typeMapping.clear(); - typeMapping.put("enum", "binary"); - typeMapping.put("date", "date"); - typeMapping.put("datetime", "datetime"); - typeMapping.put("boolean", "boolean"); - typeMapping.put("string", "binary"); - typeMapping.put("integer", "integer"); - typeMapping.put("int", "integer"); - typeMapping.put("float", "integer"); - typeMapping.put("long", "integer"); - typeMapping.put("double", "float"); - typeMapping.put("array", "list"); - typeMapping.put("map", "map"); - typeMapping.put("number", "integer"); - typeMapping.put("bigdecimal", "float"); - typeMapping.put("List", "list"); - typeMapping.put("object", "object"); - typeMapping.put("file", "file"); - typeMapping.put("binary", "binary"); - typeMapping.put("bytearray", "binary"); - typeMapping.put("byte", "binary"); - typeMapping.put("uuid", "binary"); - typeMapping.put("password", "binary"); + typeMapping.put("enum", "binary()"); + typeMapping.put("date", "calendar:date()"); + typeMapping.put("datetime", "calendar:datetime()"); + typeMapping.put("date-time", "calendar:datetime()"); + typeMapping.put("boolean", "boolean()"); + typeMapping.put("string", "binary()"); + typeMapping.put("integer", "integer()"); + typeMapping.put("int", "integer()"); + typeMapping.put("float", "integer()"); + typeMapping.put("long", "integer()"); + typeMapping.put("double", "float()"); + typeMapping.put("array", "list()"); + typeMapping.put("map", "map()"); + typeMapping.put("number", "integer()"); + typeMapping.put("bigdecimal", "float()"); + typeMapping.put("List", "list()"); + typeMapping.put("object", "binary()"); + typeMapping.put("file", "binary()"); + typeMapping.put("binary", "binary()"); + typeMapping.put("bytearray", "binary()"); + typeMapping.put("byte", "binary()"); + typeMapping.put("uuid", "binary()"); + typeMapping.put("password", "binary()"); cliOptions.clear(); cliOptions.add(new CliOption(CodegenConstants.PACKAGE_NAME, "Erlang application name (convention: lowercase).") @@ -90,6 +91,11 @@ public ErlangClientCodegen() { } + @Override + public String getTypeDeclaration(String name) { + return name + ":" + name + "()"; + } + @Override public void processOpts() { super.processOpts(); @@ -158,28 +164,19 @@ public String apiFileFolder() { return outputFolder + File.separator + sourceFolder + File.separator; } + @Override + public String modelFileFolder() { + return outputFolder + File.separator + sourceFolder + File.separator; + } @Override public String toVarName(String name) { // replace - with _ e.g. created-at => created_at name = sanitizeName(name.replaceAll("-", "_")); - - // if it's all uppper case, do nothing - if (name.matches("^[A-Z_]*$")) - return name; - - // camelize (lower first character) the variable name - // pet_id => PetId - name = camelize(name); - // for reserved word or word starting with number, append _ if (isReservedWord(name)) name = escapeReservedWord(name); - // for reserved word or word starting with number, append _ - if (name.matches("^\\d.*")) - name = "Var" + name; - return name; } 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 9aa1e4ac6af..251833e4945 100644 --- a/modules/swagger-codegen/src/main/resources/erlang-client/api.mustache +++ b/modules/swagger-codegen/src/main/resources/erlang-client/api.mustache @@ -7,11 +7,11 @@ {{#operations}} {{#operation}} - -%% {{summary}} -%% {{^notes.isEmpty}} +%% @doc {{summary}} +{{^notes.isEmpty}} %% {{notes}} -%% {{/notes.isEmpty}} +{{/notes.isEmpty}} +-spec {{operationId}}({{#allParams}}{{^-first}}, {{/-first}}{{dataType}}{{/allParams}}) -> ok. {{operationId}}({{#allParams}}{{^-first}}, {{/-first}}{{paramName}}{{/allParams}}) -> Method = {{#lowercase}}{{httpMethod}}{{/lowercase}}, Path = ["{{{replacedPathName}}}"], @@ -21,5 +21,7 @@ Opts = [], Url = hackney_url:make_url(?BASE_URL, Path, QS), hackney:request(Method, Url, Headers, Body1, Opts). + {{/operation}} + {{/operations}} diff --git a/modules/swagger-codegen/src/main/resources/erlang-client/model.mustache b/modules/swagger-codegen/src/main/resources/erlang-client/model.mustache index e69de29bb2d..3974814c812 100644 --- a/modules/swagger-codegen/src/main/resources/erlang-client/model.mustache +++ b/modules/swagger-codegen/src/main/resources/erlang-client/model.mustache @@ -0,0 +1,12 @@ +{{#models}} +{{#model}} +-module({{classname}}). + +-export_type([{{classname}}/0]). + +-type {{classname}}() :: + #{ {{#vars}}'{{name}}' => {{{datatype}}}{{#hasMore}}, + {{/hasMore}}{{/vars}} + }. +{{/model}} +{{/models}} From 876301f716eb2e9681bc3c4dd1d408340fb06e3c Mon Sep 17 00:00:00 2001 From: Tristan Sloughter Date: Thu, 14 Sep 2017 12:41:21 -0700 Subject: [PATCH 3/8] fix type specs when models are the type and support QS lists --- .../languages/ErlangClientCodegen.java | 45 ++++++++++++++++++- .../main/resources/erlang-client/api.mustache | 19 ++++++-- 2 files changed, 59 insertions(+), 5 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 68ca55eca74..ee1f328011b 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 @@ -70,11 +70,11 @@ public ErlangClientCodegen() { typeMapping.put("long", "integer()"); typeMapping.put("double", "float()"); typeMapping.put("array", "list()"); - typeMapping.put("map", "map()"); + typeMapping.put("map", "maps:map()"); typeMapping.put("number", "integer()"); typeMapping.put("bigdecimal", "float()"); typeMapping.put("List", "list()"); - typeMapping.put("object", "binary()"); + typeMapping.put("object", "maps:map()"); typeMapping.put("file", "binary()"); typeMapping.put("binary", "binary()"); typeMapping.put("bytearray", "binary()"); @@ -96,6 +96,29 @@ public String getTypeDeclaration(String name) { return name + ":" + name + "()"; } + @Override + public String getTypeDeclaration(Property p) { + String swaggerType = getSwaggerType(p); + if (typeMapping.containsKey(swaggerType)) { + return typeMapping.get(swaggerType); + } + return swaggerType; + } + + @Override + public String getSwaggerType(Property p) { + String swaggerType = super.getSwaggerType(p); + String type = null; + if(typeMapping.containsKey(swaggerType)) { + type = typeMapping.get(swaggerType); + if(languageSpecificPrimitives.contains(type)) + return (type); + } + else + type = getTypeDeclaration(toModelName(snakeCase(swaggerType))); + return type; + } + @Override public void processOpts() { super.processOpts(); @@ -131,6 +154,13 @@ public void execute(Template.Fragment fragment, Writer writer) throws IOExceptio } }); + additionalProperties.put("qsEncode", new Mustache.Lambda() { + @Override + public void execute(Template.Fragment fragment, Writer writer) throws IOException { + writer.write(qsEncode(fragment.context())); + } + }); + modelPackage = packageName; apiPackage = packageName; @@ -139,6 +169,17 @@ public void execute(Template.Fragment fragment, Writer writer) throws IOExceptio supportingFiles.add(new SupportingFile("README.mustache", "", "README.md")); } + public String qsEncode(Object o) { + String r = new String(); + CodegenParameter q = (CodegenParameter) o; + if (q.isListContainer) { + r += "[{<<\"" + q.baseName + "\">>, X} || X <- " + q.paramName + "]"; + } else { + r += "{<<\"" + q.baseName + "\">>, " + q.paramName + "}"; + } + return r; + } + @Override public String escapeReservedWord(String name) { 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 251833e4945..2d7c63285e1 100644 --- a/modules/swagger-codegen/src/main/resources/erlang-client/api.mustache +++ b/modules/swagger-codegen/src/main/resources/erlang-client/api.mustache @@ -11,16 +11,29 @@ {{^notes.isEmpty}} %% {{notes}} {{/notes.isEmpty}} --spec {{operationId}}({{#allParams}}{{^-first}}, {{/-first}}{{dataType}}{{/allParams}}) -> ok. +-spec {{operationId}}({{#allParams}}{{^-first}}, {{/-first}}{{dataType}}{{/allParams}}) -> {{#returnType}}{{returnBaseType}}{{/returnType}}{{^returnType}}ok{{/returnType}}. {{operationId}}({{#allParams}}{{^-first}}, {{/-first}}{{paramName}}{{/allParams}}) -> Method = {{#lowercase}}{{httpMethod}}{{/lowercase}}, Path = ["{{{replacedPathName}}}"], - QS = [{{^queryParams.isEmpty}}{{#queryParams}}{{^-first}}, {{/-first}}{<<"{{baseName}}">>, {{paramName}}}{{/queryParams}}{{/queryParams.isEmpty}}], + QS = lists:flatten([{{^queryParams.isEmpty}}{{#queryParams}}{{^-first}}, {{/-first}}{{#qsEncode}}{{this}}{{/qsEncode}}{{/queryParams}}{{/queryParams.isEmpty}}]), Headers = [{{^headerParams.isEmpty}}{{#headerParams}}{{^-first}}, {{/-first}}{<<"{{baseName}}">>, {{paramName}}}{{/headerParams}}{{/headerParams.isEmpty}}], Body1 = {{^formParams.isEmpty}}{form, [{{#formParams}}{{^-first}}, {{/-first}}{<<"{{baseName}}">>, {{paramName}}}{{/formParams}}]}{{/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), - hackney:request(Method, Url, Headers, Body1, Opts). + + + case hackney:request(Method, Url, Headers, Body1, Opts) of + {{#responses}} + {ok, {{code}}, RespHeaders, ClientRef} -> + case lists:keyfind(<<"Content-Type">>, 1, RespHeaders) of + {{#hasProduces}}{{#produces}} + <<"{{{mediaType}}}", _/binary>> -> + {ok, Body} = hackney:body(ClientRef), + jsx:decode(Body, [returns_maps, {labels, attempt_atom}]){{#hasMore}}; {{/hasMore}}{{/produces}} + {{/hasProduces}} + end{{^-last}}; {{/-last}} + {{/responses}} + end. {{/operation}} From 52995fa6339ba4520d6638f2a313e7307fa17522 Mon Sep 17 00:00:00 2001 From: Tristan Sloughter Date: Wed, 20 Sep 2017 10:51:31 -0700 Subject: [PATCH 4/8] make method lowercase in postprocessoperations --- .../codegen/languages/ErlangClientCodegen.java | 14 +++----------- .../src/main/resources/erlang-client/api.mustache | 2 +- 2 files changed, 4 insertions(+), 12 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 ee1f328011b..71cd3bfa5f9 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 @@ -140,13 +140,6 @@ public void processOpts() { additionalProperties.put(CodegenConstants.PACKAGE_NAME, packageName); additionalProperties.put(CodegenConstants.PACKAGE_VERSION, packageVersion); - additionalProperties.put("lowercase", new Mustache.Lambda() { - @Override - public void execute(Template.Fragment fragment, Writer writer) throws IOException { - writer.write(lowercase(fragment.execute())); - } - }); - additionalProperties.put("length", new Mustache.Lambda() { @Override public void execute(Template.Fragment fragment, Writer writer) throws IOException { @@ -268,6 +261,9 @@ public Map postProcessOperations(Map objs) { List newOs = new ArrayList(); Pattern pattern = Pattern.compile("(.*)\\{([^\\}]+)\\}(.*)"); for (CodegenOperation o : os) { + // force http method to lower case + o.httpMethod = o.httpMethod.toLowerCase(); + ArrayList pathTemplateNames = new ArrayList(); Matcher matcher = pattern.matcher(o.path); StringBuffer buffer = new StringBuffer(); @@ -297,10 +293,6 @@ public void setPackageVersion(String packageVersion) { this.packageVersion = packageVersion; } - String lowercase(String word) { - return word.toLowerCase(); - } - String length(Object o) { return Integer.toString((((ExtendedCodegenOperation) o).allParams).size()); } 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 2d7c63285e1..b1e361ba63f 100644 --- a/modules/swagger-codegen/src/main/resources/erlang-client/api.mustache +++ b/modules/swagger-codegen/src/main/resources/erlang-client/api.mustache @@ -13,7 +13,7 @@ {{/notes.isEmpty}} -spec {{operationId}}({{#allParams}}{{^-first}}, {{/-first}}{{dataType}}{{/allParams}}) -> {{#returnType}}{{returnBaseType}}{{/returnType}}{{^returnType}}ok{{/returnType}}. {{operationId}}({{#allParams}}{{^-first}}, {{/-first}}{{paramName}}{{/allParams}}) -> - Method = {{#lowercase}}{{httpMethod}}{{/lowercase}}, + Method = {{httpMethod}}, Path = ["{{{replacedPathName}}}"], QS = lists:flatten([{{^queryParams.isEmpty}}{{#queryParams}}{{^-first}}, {{/-first}}{{#qsEncode}}{{this}}{{/qsEncode}}{{/queryParams}}{{/queryParams.isEmpty}}]), Headers = [{{^headerParams.isEmpty}}{{#headerParams}}{{^-first}}, {{/-first}}{<<"{{baseName}}">>, {{paramName}}}{{/headerParams}}{{/headerParams.isEmpty}}], From d30c5308189aecee139fe76db4c263300ad60a28 Mon Sep 17 00:00:00 2001 From: Tristan Sloughter Date: Thu, 28 Sep 2017 19:21:46 -0700 Subject: [PATCH 5/8] add model encode function --- .../codegen/languages/ErlangClientCodegen.java | 4 ++++ .../src/main/resources/erlang-client/api.mustache | 3 ++- .../src/main/resources/erlang-client/model.mustache | 13 +++++++++++-- 3 files changed, 17 insertions(+), 3 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 71cd3bfa5f9..2ce23aa0ecf 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 @@ -264,6 +264,10 @@ public Map postProcessOperations(Map objs) { // force http method to lower case o.httpMethod = o.httpMethod.toLowerCase(); + if (o.isListContainer) { + o.returnType = "[" + o.returnBaseType + "]"; + } + ArrayList pathTemplateNames = new ArrayList(); Matcher matcher = pattern.matcher(o.path); StringBuffer buffer = new StringBuffer(); 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 b1e361ba63f..1e0df0fe39b 100644 --- a/modules/swagger-codegen/src/main/resources/erlang-client/api.mustache +++ b/modules/swagger-codegen/src/main/resources/erlang-client/api.mustache @@ -11,7 +11,7 @@ {{^notes.isEmpty}} %% {{notes}} {{/notes.isEmpty}} --spec {{operationId}}({{#allParams}}{{^-first}}, {{/-first}}{{dataType}}{{/allParams}}) -> {{#returnType}}{{returnBaseType}}{{/returnType}}{{^returnType}}ok{{/returnType}}. +-spec {{operationId}}({{#allParams}}{{^-first}}, {{/-first}}{{dataType}}{{/allParams}}) -> {{#returnType}}{{returnType}}{{/returnType}}{{^returnType}}ok{{/returnType}}. {{operationId}}({{#allParams}}{{^-first}}, {{/-first}}{{paramName}}{{/allParams}}) -> Method = {{httpMethod}}, Path = ["{{{replacedPathName}}}"], @@ -29,6 +29,7 @@ {{#hasProduces}}{{#produces}} <<"{{{mediaType}}}", _/binary>> -> {ok, Body} = hackney:body(ClientRef), + jsx:decode(Body, [returns_maps, {labels, attempt_atom}]){{#hasMore}}; {{/hasMore}}{{/produces}} {{/hasProduces}} end{{^-last}}; {{/-last}} diff --git a/modules/swagger-codegen/src/main/resources/erlang-client/model.mustache b/modules/swagger-codegen/src/main/resources/erlang-client/model.mustache index 3974814c812..da0e8672ca0 100644 --- a/modules/swagger-codegen/src/main/resources/erlang-client/model.mustache +++ b/modules/swagger-codegen/src/main/resources/erlang-client/model.mustache @@ -2,11 +2,20 @@ {{#model}} -module({{classname}}). --export_type([{{classname}}/0]). +-export_type([{{classname}}/0, + encode/1, + decode/1]). -type {{classname}}() :: - #{ {{#vars}}'{{name}}' => {{{datatype}}}{{#hasMore}}, + #{ {{#vars}}'{{name}}' {{#required}}:={{/required}}{{^required}}=>{{/required}} {{{datatype}}}{{#hasMore}}, {{/hasMore}}{{/vars}} }. + +encode(#{ {{#vars}}'{{name}}' := {{{nameInCamelCase}}}{{#hasMore}}, + {{/hasMore}}{{/vars}} + }) -> + #{ {{#vars}}'{{baseName}}' => {{{nameInCamelCase}}}{{#hasMore}}, + {{/hasMore}}{{/vars}} + } {{/model}} {{/models}} From bfbe52ff87efbe3eb5fcbd80c43eea4a1cb49207 Mon Sep 17 00:00:00 2001 From: Tristan Sloughter Date: Thu, 28 Sep 2017 19:23:29 -0700 Subject: [PATCH 6/8] add erlang client sample --- .../erlang-client/.swagger-codegen-ignore | 23 ++ .../erlang-client/.swagger-codegen/VERSION | 1 + .../client/petstore/erlang-client/README.md | 5 + .../petstore/erlang-client/rebar.config | 3 + .../erlang-client/src/swagger.app.src | 17 + .../src/swagger_api_response.erl | 20 ++ .../erlang-client/src/swagger_category.erl | 17 + .../erlang-client/src/swagger_order.erl | 29 ++ .../erlang-client/src/swagger_pet.erl | 29 ++ .../erlang-client/src/swagger_pet_api.erl | 301 ++++++++++++++++++ .../erlang-client/src/swagger_store_api.erl | 165 ++++++++++ .../erlang-client/src/swagger_tag.erl | 17 + .../erlang-client/src/swagger_user.erl | 35 ++ .../erlang-client/src/swagger_user_api.erl | 293 +++++++++++++++++ 14 files changed, 955 insertions(+) create mode 100644 samples/client/petstore/erlang-client/.swagger-codegen-ignore create mode 100644 samples/client/petstore/erlang-client/.swagger-codegen/VERSION create mode 100644 samples/client/petstore/erlang-client/README.md create mode 100644 samples/client/petstore/erlang-client/rebar.config create mode 100644 samples/client/petstore/erlang-client/src/swagger.app.src create mode 100644 samples/client/petstore/erlang-client/src/swagger_api_response.erl create mode 100644 samples/client/petstore/erlang-client/src/swagger_category.erl create mode 100644 samples/client/petstore/erlang-client/src/swagger_order.erl create mode 100644 samples/client/petstore/erlang-client/src/swagger_pet.erl create mode 100644 samples/client/petstore/erlang-client/src/swagger_pet_api.erl create mode 100644 samples/client/petstore/erlang-client/src/swagger_store_api.erl create mode 100644 samples/client/petstore/erlang-client/src/swagger_tag.erl create mode 100644 samples/client/petstore/erlang-client/src/swagger_user.erl create mode 100644 samples/client/petstore/erlang-client/src/swagger_user_api.erl diff --git a/samples/client/petstore/erlang-client/.swagger-codegen-ignore b/samples/client/petstore/erlang-client/.swagger-codegen-ignore new file mode 100644 index 00000000000..c5fa491b4c5 --- /dev/null +++ b/samples/client/petstore/erlang-client/.swagger-codegen-ignore @@ -0,0 +1,23 @@ +# Swagger Codegen Ignore +# Generated by swagger-codegen https://github.com/swagger-api/swagger-codegen + +# Use this file to prevent files from being overwritten by the generator. +# The patterns follow closely to .gitignore or .dockerignore. + +# As an example, the C# client generator defines ApiClient.cs. +# You can make changes and tell Swagger Codgen to ignore just this file by uncommenting the following line: +#ApiClient.cs + +# You can match any string of characters against a directory, file or extension with a single asterisk (*): +#foo/*/qux +# The above matches foo/bar/qux and foo/baz/qux, but not foo/bar/baz/qux + +# You can recursively match patterns against a directory, file or extension with a double asterisk (**): +#foo/**/qux +# This matches foo/bar/qux, foo/baz/qux, and foo/bar/baz/qux + +# You can also negate patterns with an exclamation (!). +# For example, you can ignore all files in a docs folder with the file extension .md: +#docs/*.md +# Then explicitly reverse the ignore rule for a single file: +#!docs/README.md diff --git a/samples/client/petstore/erlang-client/.swagger-codegen/VERSION b/samples/client/petstore/erlang-client/.swagger-codegen/VERSION new file mode 100644 index 00000000000..f9f7450d135 --- /dev/null +++ b/samples/client/petstore/erlang-client/.swagger-codegen/VERSION @@ -0,0 +1 @@ +2.3.0-SNAPSHOT \ No newline at end of file diff --git a/samples/client/petstore/erlang-client/README.md b/samples/client/petstore/erlang-client/README.md new file mode 100644 index 00000000000..f3eab0b5528 --- /dev/null +++ b/samples/client/petstore/erlang-client/README.md @@ -0,0 +1,5 @@ +# Swagger client server library for Erlang + +## Overview + +An Erlang client stub generated by [Swagger Codegen](https://github.com/swagger-api/swagger-codegen) given an OpenAPI/Swagger spec. diff --git a/samples/client/petstore/erlang-client/rebar.config b/samples/client/petstore/erlang-client/rebar.config new file mode 100644 index 00000000000..abe84a1a9f3 --- /dev/null +++ b/samples/client/petstore/erlang-client/rebar.config @@ -0,0 +1,3 @@ +{erl_opts, [debug_info, warnings_as_errors, warn_untyped_record]}. + +{deps, [jsx, hackney]}. diff --git a/samples/client/petstore/erlang-client/src/swagger.app.src b/samples/client/petstore/erlang-client/src/swagger.app.src new file mode 100644 index 00000000000..6547fbd34e8 --- /dev/null +++ b/samples/client/petstore/erlang-client/src/swagger.app.src @@ -0,0 +1,17 @@ +{application, swagger, + [{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, ""}, + {registered, []}, + {applications, + [kernel, + stdlib, + ssl, + hackney + ]}, + {env, []}, + {modules, []}, + + {maintainers, []}, + {licenses, ["Apache 2.0"]}, + {links, []} +]}. diff --git a/samples/client/petstore/erlang-client/src/swagger_api_response.erl b/samples/client/petstore/erlang-client/src/swagger_api_response.erl new file mode 100644 index 00000000000..33826528dc4 --- /dev/null +++ b/samples/client/petstore/erlang-client/src/swagger_api_response.erl @@ -0,0 +1,20 @@ +-module(swagger_api_response). + +-export_type([swagger_api_response/0, + encode/1, + decode/1]). + +-type swagger_api_response() :: + #{ 'code' => integer(), + 'type' => binary(), + 'message' => binary() + }. + +encode(#{ 'code' := Code, + 'type' := Type, + 'message' := Message + }) -> + #{ 'code' => Code, + 'type' => Type, + 'message' => Message + } diff --git a/samples/client/petstore/erlang-client/src/swagger_category.erl b/samples/client/petstore/erlang-client/src/swagger_category.erl new file mode 100644 index 00000000000..0bd89b55087 --- /dev/null +++ b/samples/client/petstore/erlang-client/src/swagger_category.erl @@ -0,0 +1,17 @@ +-module(swagger_category). + +-export_type([swagger_category/0, + encode/1, + decode/1]). + +-type swagger_category() :: + #{ 'id' => integer(), + 'name' => binary() + }. + +encode(#{ 'id' := Id, + 'name' := Name + }) -> + #{ 'id' => Id, + 'name' => Name + } diff --git a/samples/client/petstore/erlang-client/src/swagger_order.erl b/samples/client/petstore/erlang-client/src/swagger_order.erl new file mode 100644 index 00000000000..06a9a1a270a --- /dev/null +++ b/samples/client/petstore/erlang-client/src/swagger_order.erl @@ -0,0 +1,29 @@ +-module(swagger_order). + +-export_type([swagger_order/0, + encode/1, + decode/1]). + +-type swagger_order() :: + #{ 'id' => integer(), + 'petId' => integer(), + 'quantity' => integer(), + 'shipDate' => swagger_date_time:swagger_date_time(), + 'status' => binary(), + 'complete' => boolean() + }. + +encode(#{ 'id' := Id, + 'petId' := PetId, + 'quantity' := Quantity, + 'shipDate' := ShipDate, + 'status' := Status, + 'complete' := Complete + }) -> + #{ 'id' => Id, + 'petId' => PetId, + 'quantity' => Quantity, + 'shipDate' => ShipDate, + 'status' => Status, + 'complete' => Complete + } diff --git a/samples/client/petstore/erlang-client/src/swagger_pet.erl b/samples/client/petstore/erlang-client/src/swagger_pet.erl new file mode 100644 index 00000000000..c9484fa0fea --- /dev/null +++ b/samples/client/petstore/erlang-client/src/swagger_pet.erl @@ -0,0 +1,29 @@ +-module(swagger_pet). + +-export_type([swagger_pet/0, + encode/1, + decode/1]). + +-type swagger_pet() :: + #{ 'id' => integer(), + 'category' => swagger_category:swagger_category(), + 'name' := binary(), + 'photoUrls' := list(), + 'tags' => list(), + 'status' => binary() + }. + +encode(#{ 'id' := Id, + 'category' := Category, + 'name' := Name, + 'photoUrls' := PhotoUrls, + 'tags' := Tags, + 'status' := Status + }) -> + #{ 'id' => Id, + 'category' => Category, + 'name' => Name, + 'photoUrls' => PhotoUrls, + 'tags' => Tags, + 'status' => Status + } diff --git a/samples/client/petstore/erlang-client/src/swagger_pet_api.erl b/samples/client/petstore/erlang-client/src/swagger_pet_api.erl new file mode 100644 index 00000000000..82042b05fd2 --- /dev/null +++ b/samples/client/petstore/erlang-client/src/swagger_pet_api.erl @@ -0,0 +1,301 @@ +-module(swagger_pet_api). + +-export([add_pet/1, + delete_pet/2, + find_pets_by_status/1, + find_pets_by_tags/1, + get_pet_by_id/1, + update_pet/1, + update_pet_with_form/3, + upload_file/3]). + +-define(BASE_URL, <<"http://petstore.swagger.io/v2">>). + +%% @doc Add a new pet to the store +-spec add_pet(swagger_pet:swagger_pet()) -> ok. +add_pet(Body) -> + Method = post, + Path = ["/pet"], + QS = lists:flatten([]), + Headers = [], + Body1 = Body, + Opts = [], + Url = hackney_url:make_url(?BASE_URL, Path, QS), + + + case hackney:request(Method, Url, Headers, Body1, Opts) of + {ok, 405, RespHeaders, ClientRef} -> + case lists:keyfind(<<"Content-Type">>, 1, RespHeaders) of + + <<"application/xml", _/binary>> -> + {ok, Body} = hackney:body(ClientRef), + + jsx:decode(Body, [returns_maps, {labels, attempt_atom}]); + <<"application/json", _/binary>> -> + {ok, Body} = hackney:body(ClientRef), + + jsx:decode(Body, [returns_maps, {labels, attempt_atom}]) + end + end. + +%% @doc Deletes a pet +-spec delete_pet(integer(), binary()) -> ok. +delete_pet(PetId, ApiKey) -> + Method = delete, + Path = ["/pet/", PetId, ""], + QS = lists:flatten([]), + Headers = [{<<"api_key">>, ApiKey}], + Body1 = [], + Opts = [], + Url = hackney_url:make_url(?BASE_URL, Path, QS), + + + case hackney:request(Method, Url, Headers, Body1, Opts) of + {ok, 400, RespHeaders, ClientRef} -> + case lists:keyfind(<<"Content-Type">>, 1, RespHeaders) of + + <<"application/xml", _/binary>> -> + {ok, Body} = hackney:body(ClientRef), + + jsx:decode(Body, [returns_maps, {labels, attempt_atom}]); + <<"application/json", _/binary>> -> + {ok, Body} = hackney:body(ClientRef), + + jsx:decode(Body, [returns_maps, {labels, attempt_atom}]) + end + end. + +%% @doc Finds Pets by status +%% Multiple status values can be provided with comma separated strings +-spec find_pets_by_status(list()) -> [swagger_pet:swagger_pet()]. +find_pets_by_status(Status) -> + Method = get, + Path = ["/pet/findByStatus"], + QS = lists:flatten([[{<<"status">>, X} || X <- Status]]), + 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} -> + case lists:keyfind(<<"Content-Type">>, 1, RespHeaders) of + + <<"application/xml", _/binary>> -> + {ok, Body} = hackney:body(ClientRef), + + jsx:decode(Body, [returns_maps, {labels, attempt_atom}]); + <<"application/json", _/binary>> -> + {ok, Body} = hackney:body(ClientRef), + + jsx:decode(Body, [returns_maps, {labels, attempt_atom}]) + end; + {ok, 400, RespHeaders, ClientRef} -> + case lists:keyfind(<<"Content-Type">>, 1, RespHeaders) of + + <<"application/xml", _/binary>> -> + {ok, Body} = hackney:body(ClientRef), + + jsx:decode(Body, [returns_maps, {labels, attempt_atom}]); + <<"application/json", _/binary>> -> + {ok, Body} = hackney:body(ClientRef), + + jsx:decode(Body, [returns_maps, {labels, attempt_atom}]) + end + 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()) -> [swagger_pet:swagger_pet()]. +find_pets_by_tags(Tags) -> + Method = get, + Path = ["/pet/findByTags"], + QS = lists:flatten([[{<<"tags">>, X} || X <- Tags]]), + 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} -> + case lists:keyfind(<<"Content-Type">>, 1, RespHeaders) of + + <<"application/xml", _/binary>> -> + {ok, Body} = hackney:body(ClientRef), + + jsx:decode(Body, [returns_maps, {labels, attempt_atom}]); + <<"application/json", _/binary>> -> + {ok, Body} = hackney:body(ClientRef), + + jsx:decode(Body, [returns_maps, {labels, attempt_atom}]) + end; + {ok, 400, RespHeaders, ClientRef} -> + case lists:keyfind(<<"Content-Type">>, 1, RespHeaders) of + + <<"application/xml", _/binary>> -> + {ok, Body} = hackney:body(ClientRef), + + jsx:decode(Body, [returns_maps, {labels, attempt_atom}]); + <<"application/json", _/binary>> -> + {ok, Body} = hackney:body(ClientRef), + + jsx:decode(Body, [returns_maps, {labels, attempt_atom}]) + end + end. + +%% @doc Find pet by ID +%% Returns a single pet +-spec get_pet_by_id(integer()) -> swagger_pet:swagger_pet(). +get_pet_by_id(PetId) -> + Method = get, + Path = ["/pet/", PetId, ""], + QS = lists:flatten([]), + 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} -> + case lists:keyfind(<<"Content-Type">>, 1, RespHeaders) of + + <<"application/xml", _/binary>> -> + {ok, Body} = hackney:body(ClientRef), + + jsx:decode(Body, [returns_maps, {labels, attempt_atom}]); + <<"application/json", _/binary>> -> + {ok, Body} = hackney:body(ClientRef), + + jsx:decode(Body, [returns_maps, {labels, attempt_atom}]) + end; + {ok, 400, RespHeaders, ClientRef} -> + case lists:keyfind(<<"Content-Type">>, 1, RespHeaders) of + + <<"application/xml", _/binary>> -> + {ok, Body} = hackney:body(ClientRef), + + jsx:decode(Body, [returns_maps, {labels, attempt_atom}]); + <<"application/json", _/binary>> -> + {ok, Body} = hackney:body(ClientRef), + + jsx:decode(Body, [returns_maps, {labels, attempt_atom}]) + end; + {ok, 404, RespHeaders, ClientRef} -> + case lists:keyfind(<<"Content-Type">>, 1, RespHeaders) of + + <<"application/xml", _/binary>> -> + {ok, Body} = hackney:body(ClientRef), + + jsx:decode(Body, [returns_maps, {labels, attempt_atom}]); + <<"application/json", _/binary>> -> + {ok, Body} = hackney:body(ClientRef), + + jsx:decode(Body, [returns_maps, {labels, attempt_atom}]) + end + end. + +%% @doc Update an existing pet +-spec update_pet(swagger_pet:swagger_pet()) -> ok. +update_pet(Body) -> + Method = put, + Path = ["/pet"], + QS = lists:flatten([]), + Headers = [], + Body1 = Body, + Opts = [], + Url = hackney_url:make_url(?BASE_URL, Path, QS), + + + case hackney:request(Method, Url, Headers, Body1, Opts) of + {ok, 400, RespHeaders, ClientRef} -> + case lists:keyfind(<<"Content-Type">>, 1, RespHeaders) of + + <<"application/xml", _/binary>> -> + {ok, Body} = hackney:body(ClientRef), + + jsx:decode(Body, [returns_maps, {labels, attempt_atom}]); + <<"application/json", _/binary>> -> + {ok, Body} = hackney:body(ClientRef), + + jsx:decode(Body, [returns_maps, {labels, attempt_atom}]) + end; + {ok, 404, RespHeaders, ClientRef} -> + case lists:keyfind(<<"Content-Type">>, 1, RespHeaders) of + + <<"application/xml", _/binary>> -> + {ok, Body} = hackney:body(ClientRef), + + jsx:decode(Body, [returns_maps, {labels, attempt_atom}]); + <<"application/json", _/binary>> -> + {ok, Body} = hackney:body(ClientRef), + + jsx:decode(Body, [returns_maps, {labels, attempt_atom}]) + end; + {ok, 405, RespHeaders, ClientRef} -> + case lists:keyfind(<<"Content-Type">>, 1, RespHeaders) of + + <<"application/xml", _/binary>> -> + {ok, Body} = hackney:body(ClientRef), + + jsx:decode(Body, [returns_maps, {labels, attempt_atom}]); + <<"application/json", _/binary>> -> + {ok, Body} = hackney:body(ClientRef), + + jsx:decode(Body, [returns_maps, {labels, attempt_atom}]) + end + end. + +%% @doc Updates a pet in the store with form data +-spec update_pet_with_form(integer(), binary(), binary()) -> ok. +update_pet_with_form(PetId, Name, Status) -> + Method = post, + Path = ["/pet/", PetId, ""], + QS = lists:flatten([]), + Headers = [], + Body1 = {form, [{<<"name">>, Name}, {<<"status">>, Status}]}, + Opts = [], + Url = hackney_url:make_url(?BASE_URL, Path, QS), + + + case hackney:request(Method, Url, Headers, Body1, Opts) of + {ok, 405, RespHeaders, ClientRef} -> + case lists:keyfind(<<"Content-Type">>, 1, RespHeaders) of + + <<"application/xml", _/binary>> -> + {ok, Body} = hackney:body(ClientRef), + + jsx:decode(Body, [returns_maps, {labels, attempt_atom}]); + <<"application/json", _/binary>> -> + {ok, Body} = hackney:body(ClientRef), + + jsx:decode(Body, [returns_maps, {labels, attempt_atom}]) + end + end. + +%% @doc uploads an image +-spec upload_file(integer(), binary(), binary()) -> swagger_api_response:swagger_api_response(). +upload_file(PetId, AdditionalMetadata, File) -> + Method = post, + Path = ["/pet/", PetId, "/uploadImage"], + QS = lists:flatten([]), + Headers = [], + Body1 = {form, [{<<"additionalMetadata">>, AdditionalMetadata}, {<<"file">>, File}]}, + Opts = [], + Url = hackney_url:make_url(?BASE_URL, Path, QS), + + + case hackney:request(Method, Url, Headers, Body1, Opts) of + {ok, 200, RespHeaders, ClientRef} -> + case lists:keyfind(<<"Content-Type">>, 1, RespHeaders) of + + <<"application/json", _/binary>> -> + {ok, Body} = hackney:body(ClientRef), + + jsx:decode(Body, [returns_maps, {labels, attempt_atom}]) + end + 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 new file mode 100644 index 00000000000..deee0a29279 --- /dev/null +++ b/samples/client/petstore/erlang-client/src/swagger_store_api.erl @@ -0,0 +1,165 @@ +-module(swagger_store_api). + +-export([delete_order/1, + get_inventory/0, + get_order_by_id/1, + place_order/1]). + +-define(BASE_URL, <<"http://petstore.swagger.io/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. +delete_order(OrderId) -> + Method = delete, + Path = ["/store/order/", OrderId, ""], + QS = lists:flatten([]), + Headers = [], + Body1 = [], + Opts = [], + Url = hackney_url:make_url(?BASE_URL, Path, QS), + + + case hackney:request(Method, Url, Headers, Body1, Opts) of + {ok, 400, RespHeaders, ClientRef} -> + case lists:keyfind(<<"Content-Type">>, 1, RespHeaders) of + + <<"application/xml", _/binary>> -> + {ok, Body} = hackney:body(ClientRef), + + jsx:decode(Body, [returns_maps, {labels, attempt_atom}]); + <<"application/json", _/binary>> -> + {ok, Body} = hackney:body(ClientRef), + + jsx:decode(Body, [returns_maps, {labels, attempt_atom}]) + end; + {ok, 404, RespHeaders, ClientRef} -> + case lists:keyfind(<<"Content-Type">>, 1, RespHeaders) of + + <<"application/xml", _/binary>> -> + {ok, Body} = hackney:body(ClientRef), + + jsx:decode(Body, [returns_maps, {labels, attempt_atom}]); + <<"application/json", _/binary>> -> + {ok, Body} = hackney:body(ClientRef), + + jsx:decode(Body, [returns_maps, {labels, attempt_atom}]) + end + end. + +%% @doc Returns pet inventories by status +%% Returns a map of status codes to quantities +-spec get_inventory() -> maps:map(). +get_inventory() -> + Method = get, + Path = ["/store/inventory"], + QS = lists:flatten([]), + 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} -> + case lists:keyfind(<<"Content-Type">>, 1, RespHeaders) of + + <<"application/json", _/binary>> -> + {ok, Body} = hackney:body(ClientRef), + + jsx:decode(Body, [returns_maps, {labels, attempt_atom}]) + end + 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()) -> swagger_order:swagger_order(). +get_order_by_id(OrderId) -> + Method = get, + Path = ["/store/order/", OrderId, ""], + QS = lists:flatten([]), + 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} -> + case lists:keyfind(<<"Content-Type">>, 1, RespHeaders) of + + <<"application/xml", _/binary>> -> + {ok, Body} = hackney:body(ClientRef), + + jsx:decode(Body, [returns_maps, {labels, attempt_atom}]); + <<"application/json", _/binary>> -> + {ok, Body} = hackney:body(ClientRef), + + jsx:decode(Body, [returns_maps, {labels, attempt_atom}]) + end; + {ok, 400, RespHeaders, ClientRef} -> + case lists:keyfind(<<"Content-Type">>, 1, RespHeaders) of + + <<"application/xml", _/binary>> -> + {ok, Body} = hackney:body(ClientRef), + + jsx:decode(Body, [returns_maps, {labels, attempt_atom}]); + <<"application/json", _/binary>> -> + {ok, Body} = hackney:body(ClientRef), + + jsx:decode(Body, [returns_maps, {labels, attempt_atom}]) + end; + {ok, 404, RespHeaders, ClientRef} -> + case lists:keyfind(<<"Content-Type">>, 1, RespHeaders) of + + <<"application/xml", _/binary>> -> + {ok, Body} = hackney:body(ClientRef), + + jsx:decode(Body, [returns_maps, {labels, attempt_atom}]); + <<"application/json", _/binary>> -> + {ok, Body} = hackney:body(ClientRef), + + jsx:decode(Body, [returns_maps, {labels, attempt_atom}]) + end + end. + +%% @doc Place an order for a pet +-spec place_order(swagger_order:swagger_order()) -> swagger_order:swagger_order(). +place_order(Body) -> + Method = post, + Path = ["/store/order"], + QS = lists:flatten([]), + 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} -> + case lists:keyfind(<<"Content-Type">>, 1, RespHeaders) of + + <<"application/xml", _/binary>> -> + {ok, Body} = hackney:body(ClientRef), + + jsx:decode(Body, [returns_maps, {labels, attempt_atom}]); + <<"application/json", _/binary>> -> + {ok, Body} = hackney:body(ClientRef), + + jsx:decode(Body, [returns_maps, {labels, attempt_atom}]) + end; + {ok, 400, RespHeaders, ClientRef} -> + case lists:keyfind(<<"Content-Type">>, 1, RespHeaders) of + + <<"application/xml", _/binary>> -> + {ok, Body} = hackney:body(ClientRef), + + jsx:decode(Body, [returns_maps, {labels, attempt_atom}]); + <<"application/json", _/binary>> -> + {ok, Body} = hackney:body(ClientRef), + + jsx:decode(Body, [returns_maps, {labels, attempt_atom}]) + end + end. + + diff --git a/samples/client/petstore/erlang-client/src/swagger_tag.erl b/samples/client/petstore/erlang-client/src/swagger_tag.erl new file mode 100644 index 00000000000..5abdf9b959f --- /dev/null +++ b/samples/client/petstore/erlang-client/src/swagger_tag.erl @@ -0,0 +1,17 @@ +-module(swagger_tag). + +-export_type([swagger_tag/0, + encode/1, + decode/1]). + +-type swagger_tag() :: + #{ 'id' => integer(), + 'name' => binary() + }. + +encode(#{ 'id' := Id, + 'name' := Name + }) -> + #{ 'id' => Id, + 'name' => Name + } diff --git a/samples/client/petstore/erlang-client/src/swagger_user.erl b/samples/client/petstore/erlang-client/src/swagger_user.erl new file mode 100644 index 00000000000..8c82c40488e --- /dev/null +++ b/samples/client/petstore/erlang-client/src/swagger_user.erl @@ -0,0 +1,35 @@ +-module(swagger_user). + +-export_type([swagger_user/0, + encode/1, + decode/1]). + +-type swagger_user() :: + #{ 'id' => integer(), + 'username' => binary(), + 'firstName' => binary(), + 'lastName' => binary(), + 'email' => binary(), + 'password' => binary(), + 'phone' => binary(), + 'userStatus' => integer() + }. + +encode(#{ 'id' := Id, + 'username' := Username, + 'firstName' := FirstName, + 'lastName' := LastName, + 'email' := Email, + 'password' := Password, + 'phone' := Phone, + 'userStatus' := UserStatus + }) -> + #{ 'id' => Id, + 'username' => Username, + 'firstName' => FirstName, + 'lastName' => LastName, + 'email' => Email, + 'password' => Password, + 'phone' => Phone, + 'userStatus' => UserStatus + } diff --git a/samples/client/petstore/erlang-client/src/swagger_user_api.erl b/samples/client/petstore/erlang-client/src/swagger_user_api.erl new file mode 100644 index 00000000000..12770e465ed --- /dev/null +++ b/samples/client/petstore/erlang-client/src/swagger_user_api.erl @@ -0,0 +1,293 @@ +-module(swagger_user_api). + +-export([create_user/1, + create_users_with_array_input/1, + create_users_with_list_input/1, + delete_user/1, + get_user_by_name/1, + login_user/2, + logout_user/0, + update_user/2]). + +-define(BASE_URL, <<"http://petstore.swagger.io/v2">>). + +%% @doc Create user +%% This can only be done by the logged in user. +-spec create_user(swagger_user:swagger_user()) -> ok. +create_user(Body) -> + Method = post, + Path = ["/user"], + QS = lists:flatten([]), + Headers = [], + Body1 = Body, + Opts = [], + Url = hackney_url:make_url(?BASE_URL, Path, QS), + + + case hackney:request(Method, Url, Headers, Body1, Opts) of + {ok, 0, RespHeaders, ClientRef} -> + case lists:keyfind(<<"Content-Type">>, 1, RespHeaders) of + + <<"application/xml", _/binary>> -> + {ok, Body} = hackney:body(ClientRef), + + jsx:decode(Body, [returns_maps, {labels, attempt_atom}]); + <<"application/json", _/binary>> -> + {ok, Body} = hackney:body(ClientRef), + + jsx:decode(Body, [returns_maps, {labels, attempt_atom}]) + end + end. + +%% @doc Creates list of users with given input array +-spec create_users_with_array_input(list()) -> ok. +create_users_with_array_input(Body) -> + Method = post, + Path = ["/user/createWithArray"], + QS = lists:flatten([]), + Headers = [], + Body1 = Body, + Opts = [], + Url = hackney_url:make_url(?BASE_URL, Path, QS), + + + case hackney:request(Method, Url, Headers, Body1, Opts) of + {ok, 0, RespHeaders, ClientRef} -> + case lists:keyfind(<<"Content-Type">>, 1, RespHeaders) of + + <<"application/xml", _/binary>> -> + {ok, Body} = hackney:body(ClientRef), + + jsx:decode(Body, [returns_maps, {labels, attempt_atom}]); + <<"application/json", _/binary>> -> + {ok, Body} = hackney:body(ClientRef), + + jsx:decode(Body, [returns_maps, {labels, attempt_atom}]) + end + end. + +%% @doc Creates list of users with given input array +-spec create_users_with_list_input(list()) -> ok. +create_users_with_list_input(Body) -> + Method = post, + Path = ["/user/createWithList"], + QS = lists:flatten([]), + Headers = [], + Body1 = Body, + Opts = [], + Url = hackney_url:make_url(?BASE_URL, Path, QS), + + + case hackney:request(Method, Url, Headers, Body1, Opts) of + {ok, 0, RespHeaders, ClientRef} -> + case lists:keyfind(<<"Content-Type">>, 1, RespHeaders) of + + <<"application/xml", _/binary>> -> + {ok, Body} = hackney:body(ClientRef), + + jsx:decode(Body, [returns_maps, {labels, attempt_atom}]); + <<"application/json", _/binary>> -> + {ok, Body} = hackney:body(ClientRef), + + jsx:decode(Body, [returns_maps, {labels, attempt_atom}]) + end + end. + +%% @doc Delete user +%% This can only be done by the logged in user. +-spec delete_user(binary()) -> ok. +delete_user(Username) -> + Method = delete, + Path = ["/user/", Username, ""], + QS = lists:flatten([]), + Headers = [], + Body1 = [], + Opts = [], + Url = hackney_url:make_url(?BASE_URL, Path, QS), + + + case hackney:request(Method, Url, Headers, Body1, Opts) of + {ok, 400, RespHeaders, ClientRef} -> + case lists:keyfind(<<"Content-Type">>, 1, RespHeaders) of + + <<"application/xml", _/binary>> -> + {ok, Body} = hackney:body(ClientRef), + + jsx:decode(Body, [returns_maps, {labels, attempt_atom}]); + <<"application/json", _/binary>> -> + {ok, Body} = hackney:body(ClientRef), + + jsx:decode(Body, [returns_maps, {labels, attempt_atom}]) + end; + {ok, 404, RespHeaders, ClientRef} -> + case lists:keyfind(<<"Content-Type">>, 1, RespHeaders) of + + <<"application/xml", _/binary>> -> + {ok, Body} = hackney:body(ClientRef), + + jsx:decode(Body, [returns_maps, {labels, attempt_atom}]); + <<"application/json", _/binary>> -> + {ok, Body} = hackney:body(ClientRef), + + jsx:decode(Body, [returns_maps, {labels, attempt_atom}]) + end + end. + +%% @doc Get user by user name +-spec get_user_by_name(binary()) -> swagger_user:swagger_user(). +get_user_by_name(Username) -> + Method = get, + Path = ["/user/", Username, ""], + QS = lists:flatten([]), + 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} -> + case lists:keyfind(<<"Content-Type">>, 1, RespHeaders) of + + <<"application/xml", _/binary>> -> + {ok, Body} = hackney:body(ClientRef), + + jsx:decode(Body, [returns_maps, {labels, attempt_atom}]); + <<"application/json", _/binary>> -> + {ok, Body} = hackney:body(ClientRef), + + jsx:decode(Body, [returns_maps, {labels, attempt_atom}]) + end; + {ok, 400, RespHeaders, ClientRef} -> + case lists:keyfind(<<"Content-Type">>, 1, RespHeaders) of + + <<"application/xml", _/binary>> -> + {ok, Body} = hackney:body(ClientRef), + + jsx:decode(Body, [returns_maps, {labels, attempt_atom}]); + <<"application/json", _/binary>> -> + {ok, Body} = hackney:body(ClientRef), + + jsx:decode(Body, [returns_maps, {labels, attempt_atom}]) + end; + {ok, 404, RespHeaders, ClientRef} -> + case lists:keyfind(<<"Content-Type">>, 1, RespHeaders) of + + <<"application/xml", _/binary>> -> + {ok, Body} = hackney:body(ClientRef), + + jsx:decode(Body, [returns_maps, {labels, attempt_atom}]); + <<"application/json", _/binary>> -> + {ok, Body} = hackney:body(ClientRef), + + jsx:decode(Body, [returns_maps, {labels, attempt_atom}]) + end + end. + +%% @doc Logs user into the system +-spec login_user(binary(), binary()) -> binary(). +login_user(Username, Password) -> + Method = get, + Path = ["/user/login"], + QS = lists:flatten([{<<"username">>, Username}, {<<"password">>, Password}]), + 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} -> + case lists:keyfind(<<"Content-Type">>, 1, RespHeaders) of + + <<"application/xml", _/binary>> -> + {ok, Body} = hackney:body(ClientRef), + + jsx:decode(Body, [returns_maps, {labels, attempt_atom}]); + <<"application/json", _/binary>> -> + {ok, Body} = hackney:body(ClientRef), + + jsx:decode(Body, [returns_maps, {labels, attempt_atom}]) + end; + {ok, 400, RespHeaders, ClientRef} -> + case lists:keyfind(<<"Content-Type">>, 1, RespHeaders) of + + <<"application/xml", _/binary>> -> + {ok, Body} = hackney:body(ClientRef), + + jsx:decode(Body, [returns_maps, {labels, attempt_atom}]); + <<"application/json", _/binary>> -> + {ok, Body} = hackney:body(ClientRef), + + jsx:decode(Body, [returns_maps, {labels, attempt_atom}]) + end + end. + +%% @doc Logs out current logged in user session +-spec logout_user() -> ok. +logout_user() -> + Method = get, + Path = ["/user/logout"], + QS = lists:flatten([]), + Headers = [], + Body1 = [], + Opts = [], + Url = hackney_url:make_url(?BASE_URL, Path, QS), + + + case hackney:request(Method, Url, Headers, Body1, Opts) of + {ok, 0, RespHeaders, ClientRef} -> + case lists:keyfind(<<"Content-Type">>, 1, RespHeaders) of + + <<"application/xml", _/binary>> -> + {ok, Body} = hackney:body(ClientRef), + + jsx:decode(Body, [returns_maps, {labels, attempt_atom}]); + <<"application/json", _/binary>> -> + {ok, Body} = hackney:body(ClientRef), + + jsx:decode(Body, [returns_maps, {labels, attempt_atom}]) + end + end. + +%% @doc Updated user +%% This can only be done by the logged in user. +-spec update_user(binary(), swagger_user:swagger_user()) -> ok. +update_user(Username, Body) -> + Method = put, + Path = ["/user/", Username, ""], + QS = lists:flatten([]), + Headers = [], + Body1 = Body, + Opts = [], + Url = hackney_url:make_url(?BASE_URL, Path, QS), + + + case hackney:request(Method, Url, Headers, Body1, Opts) of + {ok, 400, RespHeaders, ClientRef} -> + case lists:keyfind(<<"Content-Type">>, 1, RespHeaders) of + + <<"application/xml", _/binary>> -> + {ok, Body} = hackney:body(ClientRef), + + jsx:decode(Body, [returns_maps, {labels, attempt_atom}]); + <<"application/json", _/binary>> -> + {ok, Body} = hackney:body(ClientRef), + + jsx:decode(Body, [returns_maps, {labels, attempt_atom}]) + end; + {ok, 404, RespHeaders, ClientRef} -> + case lists:keyfind(<<"Content-Type">>, 1, RespHeaders) of + + <<"application/xml", _/binary>> -> + {ok, Body} = hackney:body(ClientRef), + + jsx:decode(Body, [returns_maps, {labels, attempt_atom}]); + <<"application/json", _/binary>> -> + {ok, Body} = hackney:body(ClientRef), + + jsx:decode(Body, [returns_maps, {labels, attempt_atom}]) + end + end. + + From 7904ec167ab6ebb0a6f1924fc124ea1f15e64198 Mon Sep 17 00:00:00 2001 From: Tristan Sloughter Date: Thu, 28 Sep 2017 19:29:15 -0700 Subject: [PATCH 7/8] add windows client sample script --- bin/windows/erlang-petstore-client.bat | 10 ++++++++++ 1 file changed, 10 insertions(+) create mode 100755 bin/windows/erlang-petstore-client.bat diff --git a/bin/windows/erlang-petstore-client.bat b/bin/windows/erlang-petstore-client.bat new file mode 100755 index 00000000000..228c0c7ca46 --- /dev/null +++ b/bin/windows/erlang-petstore-client.bat @@ -0,0 +1,10 @@ +set executable=.\modules\swagger-codegen-cli\target\swagger-codegen-cli.jar + +If Not Exist %executable% ( + mvn clean package +) + +REM set JAVA_OPTS=%JAVA_OPTS% -Xmx1024M +set 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 + +java %JAVA_OPTS% -jar %executable% %ags% From cd8fc56200d04708de39ec92cb08b071cd646eab Mon Sep 17 00:00:00 2001 From: Tristan Sloughter Date: Wed, 18 Oct 2017 21:18:13 -0700 Subject: [PATCH 8/8] proper return type spec and handle return error messages --- .../main/resources/erlang-client/api.mustache | 29 ++- .../erlang-client/src/swagger_pet_api.erl | 228 ++++-------------- .../erlang-client/src/swagger_store_api.erl | 125 ++-------- .../erlang-client/src/swagger_user_api.erl | 226 ++++------------- 4 files changed, 137 insertions(+), 471 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 1e0df0fe39b..a14ee991912 100644 --- a/modules/swagger-codegen/src/main/resources/erlang-client/api.mustache +++ b/modules/swagger-codegen/src/main/resources/erlang-client/api.mustache @@ -11,29 +11,36 @@ {{^notes.isEmpty}} %% {{notes}} {{/notes.isEmpty}} --spec {{operationId}}({{#allParams}}{{^-first}}, {{/-first}}{{dataType}}{{/allParams}}) -> {{#returnType}}{{returnType}}{{/returnType}}{{^returnType}}ok{{/returnType}}. +-spec {{operationId}}({{#allParams}}{{^-first}}, {{/-first}}{{dataType}}{{/allParams}}) -> {{#returnType}}{ok, list(), {{returnType}}} | {error, string()}{{/returnType}}{{^returnType}}ok | {error, integer()}{{/returnType}}. {{operationId}}({{#allParams}}{{^-first}}, {{/-first}}{{paramName}}{{/allParams}}) -> Method = {{httpMethod}}, Path = ["{{{replacedPathName}}}"], - QS = lists:flatten([{{^queryParams.isEmpty}}{{#queryParams}}{{^-first}}, {{/-first}}{{#qsEncode}}{{this}}{{/qsEncode}}{{/queryParams}}{{/queryParams.isEmpty}}]), + QS = {{#queryParams.isEmpty}}[]{{/queryParams.isEmpty}}{{^queryParams.isEmpty}}lists:flatten([{{#queryParams}}{{^-first}}, {{/-first}}{{#qsEncode}}{{this}}{{/qsEncode}}{{/queryParams}}]){{/queryParams.isEmpty}}, Headers = [{{^headerParams.isEmpty}}{{#headerParams}}{{^-first}}, {{/-first}}{<<"{{baseName}}">>, {{paramName}}}{{/headerParams}}{{/headerParams.isEmpty}}], Body1 = {{^formParams.isEmpty}}{form, [{{#formParams}}{{^-first}}, {{/-first}}{<<"{{baseName}}">>, {{paramName}}}{{/formParams}}]}{{/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} -> - case lists:keyfind(<<"Content-Type">>, 1, RespHeaders) of - {{#hasProduces}}{{#produces}} - <<"{{{mediaType}}}", _/binary>> -> - {ok, Body} = hackney:body(ClientRef), - - jsx:decode(Body, [returns_maps, {labels, attempt_atom}]){{#hasMore}}; {{/hasMore}}{{/produces}} - {{/hasProduces}} - end{{^-last}}; {{/-last}} + {ok, Body} = hackney:body(ClientRef), + {ok, RespHeaders, jsx:decode(Body, [returns_maps, {labels, attempt_atom}])}{{#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. {{/operation}} 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 82042b05fd2..7eaef8fed81 100644 --- a/samples/client/petstore/erlang-client/src/swagger_pet_api.erl +++ b/samples/client/petstore/erlang-client/src/swagger_pet_api.erl @@ -12,62 +12,44 @@ -define(BASE_URL, <<"http://petstore.swagger.io/v2">>). %% @doc Add a new pet to the store --spec add_pet(swagger_pet:swagger_pet()) -> ok. +-spec add_pet(swagger_pet:swagger_pet()) -> ok | {error, integer()}. add_pet(Body) -> Method = post, Path = ["/pet"], - QS = lists:flatten([]), + QS = [], Headers = [], Body1 = Body, Opts = [], Url = hackney_url:make_url(?BASE_URL, Path, QS), - case hackney:request(Method, Url, Headers, Body1, Opts) of - {ok, 405, RespHeaders, ClientRef} -> - case lists:keyfind(<<"Content-Type">>, 1, RespHeaders) of - - <<"application/xml", _/binary>> -> - {ok, Body} = hackney:body(ClientRef), - - jsx:decode(Body, [returns_maps, {labels, attempt_atom}]); - <<"application/json", _/binary>> -> - {ok, Body} = hackney:body(ClientRef), - - jsx:decode(Body, [returns_maps, {labels, attempt_atom}]) - end + {ok, 200, _RespHeaders, _ClientRef} -> + ok; + {ok, Status, _RespHeaders, _ClientRef} -> + {error, Status} end. %% @doc Deletes a pet --spec delete_pet(integer(), binary()) -> ok. +-spec delete_pet(integer(), binary()) -> ok | {error, integer()}. delete_pet(PetId, ApiKey) -> Method = delete, Path = ["/pet/", PetId, ""], - QS = lists:flatten([]), + QS = [], Headers = [{<<"api_key">>, ApiKey}], Body1 = [], Opts = [], Url = hackney_url:make_url(?BASE_URL, Path, QS), - case hackney:request(Method, Url, Headers, Body1, Opts) of - {ok, 400, RespHeaders, ClientRef} -> - case lists:keyfind(<<"Content-Type">>, 1, RespHeaders) of - - <<"application/xml", _/binary>> -> - {ok, Body} = hackney:body(ClientRef), - - jsx:decode(Body, [returns_maps, {labels, attempt_atom}]); - <<"application/json", _/binary>> -> - {ok, Body} = hackney:body(ClientRef), - - jsx:decode(Body, [returns_maps, {labels, attempt_atom}]) - end + {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()) -> [swagger_pet:swagger_pet()]. +-spec find_pets_by_status(list()) -> {ok, list(), [swagger_pet:swagger_pet()]} | {error, string()}. find_pets_by_status(Status) -> Method = get, Path = ["/pet/findByStatus"], @@ -77,37 +59,17 @@ find_pets_by_status(Status) -> Opts = [], Url = hackney_url:make_url(?BASE_URL, Path, QS), - case hackney:request(Method, Url, Headers, Body1, Opts) of {ok, 200, RespHeaders, ClientRef} -> - case lists:keyfind(<<"Content-Type">>, 1, RespHeaders) of - - <<"application/xml", _/binary>> -> - {ok, Body} = hackney:body(ClientRef), - - jsx:decode(Body, [returns_maps, {labels, attempt_atom}]); - <<"application/json", _/binary>> -> - {ok, Body} = hackney:body(ClientRef), - - jsx:decode(Body, [returns_maps, {labels, attempt_atom}]) - end; - {ok, 400, RespHeaders, ClientRef} -> - case lists:keyfind(<<"Content-Type">>, 1, RespHeaders) of - - <<"application/xml", _/binary>> -> - {ok, Body} = hackney:body(ClientRef), - - jsx:decode(Body, [returns_maps, {labels, attempt_atom}]); - <<"application/json", _/binary>> -> - {ok, Body} = hackney:body(ClientRef), - - jsx:decode(Body, [returns_maps, {labels, attempt_atom}]) - end + {ok, Body} = hackney:body(ClientRef), + {ok, RespHeaders, jsx:decode(Body, [returns_maps, {labels, attempt_atom}])}; + {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()) -> [swagger_pet:swagger_pet()]. +-spec find_pets_by_tags(list()) -> {ok, list(), [swagger_pet:swagger_pet()]} | {error, string()}. find_pets_by_tags(Tags) -> Method = get, Path = ["/pet/findByTags"], @@ -117,185 +79,87 @@ find_pets_by_tags(Tags) -> Opts = [], Url = hackney_url:make_url(?BASE_URL, Path, QS), - case hackney:request(Method, Url, Headers, Body1, Opts) of {ok, 200, RespHeaders, ClientRef} -> - case lists:keyfind(<<"Content-Type">>, 1, RespHeaders) of - - <<"application/xml", _/binary>> -> - {ok, Body} = hackney:body(ClientRef), - - jsx:decode(Body, [returns_maps, {labels, attempt_atom}]); - <<"application/json", _/binary>> -> - {ok, Body} = hackney:body(ClientRef), - - jsx:decode(Body, [returns_maps, {labels, attempt_atom}]) - end; - {ok, 400, RespHeaders, ClientRef} -> - case lists:keyfind(<<"Content-Type">>, 1, RespHeaders) of - - <<"application/xml", _/binary>> -> - {ok, Body} = hackney:body(ClientRef), - - jsx:decode(Body, [returns_maps, {labels, attempt_atom}]); - <<"application/json", _/binary>> -> - {ok, Body} = hackney:body(ClientRef), - - jsx:decode(Body, [returns_maps, {labels, attempt_atom}]) - end + {ok, Body} = hackney:body(ClientRef), + {ok, RespHeaders, jsx:decode(Body, [returns_maps, {labels, attempt_atom}])}; + {ok, 400, _RespHeaders, _ClientRef} -> + {error, "Invalid tag value"} end. %% @doc Find pet by ID %% Returns a single pet --spec get_pet_by_id(integer()) -> swagger_pet:swagger_pet(). +-spec get_pet_by_id(integer()) -> {ok, list(), swagger_pet:swagger_pet()} | {error, string()}. get_pet_by_id(PetId) -> Method = get, Path = ["/pet/", PetId, ""], - QS = lists:flatten([]), + 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} -> - case lists:keyfind(<<"Content-Type">>, 1, RespHeaders) of - - <<"application/xml", _/binary>> -> - {ok, Body} = hackney:body(ClientRef), - - jsx:decode(Body, [returns_maps, {labels, attempt_atom}]); - <<"application/json", _/binary>> -> - {ok, Body} = hackney:body(ClientRef), - - jsx:decode(Body, [returns_maps, {labels, attempt_atom}]) - end; - {ok, 400, RespHeaders, ClientRef} -> - case lists:keyfind(<<"Content-Type">>, 1, RespHeaders) of - - <<"application/xml", _/binary>> -> - {ok, Body} = hackney:body(ClientRef), - - jsx:decode(Body, [returns_maps, {labels, attempt_atom}]); - <<"application/json", _/binary>> -> - {ok, Body} = hackney:body(ClientRef), - - jsx:decode(Body, [returns_maps, {labels, attempt_atom}]) - end; - {ok, 404, RespHeaders, ClientRef} -> - case lists:keyfind(<<"Content-Type">>, 1, RespHeaders) of - - <<"application/xml", _/binary>> -> - {ok, Body} = hackney:body(ClientRef), - - jsx:decode(Body, [returns_maps, {labels, attempt_atom}]); - <<"application/json", _/binary>> -> - {ok, Body} = hackney:body(ClientRef), - - jsx:decode(Body, [returns_maps, {labels, attempt_atom}]) - end + {ok, Body} = hackney:body(ClientRef), + {ok, RespHeaders, jsx:decode(Body, [returns_maps, {labels, attempt_atom}])}; + {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. +-spec update_pet(swagger_pet:swagger_pet()) -> ok | {error, integer()}. update_pet(Body) -> Method = put, Path = ["/pet"], - QS = lists:flatten([]), + QS = [], Headers = [], Body1 = Body, Opts = [], Url = hackney_url:make_url(?BASE_URL, Path, QS), - case hackney:request(Method, Url, Headers, Body1, Opts) of - {ok, 400, RespHeaders, ClientRef} -> - case lists:keyfind(<<"Content-Type">>, 1, RespHeaders) of - - <<"application/xml", _/binary>> -> - {ok, Body} = hackney:body(ClientRef), - - jsx:decode(Body, [returns_maps, {labels, attempt_atom}]); - <<"application/json", _/binary>> -> - {ok, Body} = hackney:body(ClientRef), - - jsx:decode(Body, [returns_maps, {labels, attempt_atom}]) - end; - {ok, 404, RespHeaders, ClientRef} -> - case lists:keyfind(<<"Content-Type">>, 1, RespHeaders) of - - <<"application/xml", _/binary>> -> - {ok, Body} = hackney:body(ClientRef), - - jsx:decode(Body, [returns_maps, {labels, attempt_atom}]); - <<"application/json", _/binary>> -> - {ok, Body} = hackney:body(ClientRef), - - jsx:decode(Body, [returns_maps, {labels, attempt_atom}]) - end; - {ok, 405, RespHeaders, ClientRef} -> - case lists:keyfind(<<"Content-Type">>, 1, RespHeaders) of - - <<"application/xml", _/binary>> -> - {ok, Body} = hackney:body(ClientRef), - - jsx:decode(Body, [returns_maps, {labels, attempt_atom}]); - <<"application/json", _/binary>> -> - {ok, Body} = hackney:body(ClientRef), - - jsx:decode(Body, [returns_maps, {labels, attempt_atom}]) - end + {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(), binary(), binary()) -> ok. +-spec update_pet_with_form(integer(), binary(), binary()) -> ok | {error, integer()}. update_pet_with_form(PetId, Name, Status) -> Method = post, Path = ["/pet/", PetId, ""], - QS = lists:flatten([]), + QS = [], Headers = [], Body1 = {form, [{<<"name">>, Name}, {<<"status">>, Status}]}, Opts = [], Url = hackney_url:make_url(?BASE_URL, Path, QS), - case hackney:request(Method, Url, Headers, Body1, Opts) of - {ok, 405, RespHeaders, ClientRef} -> - case lists:keyfind(<<"Content-Type">>, 1, RespHeaders) of - - <<"application/xml", _/binary>> -> - {ok, Body} = hackney:body(ClientRef), - - jsx:decode(Body, [returns_maps, {labels, attempt_atom}]); - <<"application/json", _/binary>> -> - {ok, Body} = hackney:body(ClientRef), - - jsx:decode(Body, [returns_maps, {labels, attempt_atom}]) - end + {ok, 200, _RespHeaders, _ClientRef} -> + ok; + {ok, Status, _RespHeaders, _ClientRef} -> + {error, Status} end. %% @doc uploads an image --spec upload_file(integer(), binary(), binary()) -> swagger_api_response:swagger_api_response(). +-spec upload_file(integer(), binary(), binary()) -> {ok, list(), swagger_api_response:swagger_api_response()} | {error, string()}. upload_file(PetId, AdditionalMetadata, File) -> Method = post, Path = ["/pet/", PetId, "/uploadImage"], - QS = lists:flatten([]), + QS = [], Headers = [], Body1 = {form, [{<<"additionalMetadata">>, AdditionalMetadata}, {<<"file">>, File}]}, Opts = [], Url = hackney_url:make_url(?BASE_URL, Path, QS), - case hackney:request(Method, Url, Headers, Body1, Opts) of {ok, 200, RespHeaders, ClientRef} -> - case lists:keyfind(<<"Content-Type">>, 1, RespHeaders) of - - <<"application/json", _/binary>> -> - {ok, Body} = hackney:body(ClientRef), - - jsx:decode(Body, [returns_maps, {labels, attempt_atom}]) - end + {ok, Body} = hackney:body(ClientRef), + {ok, RespHeaders, jsx:decode(Body, [returns_maps, {labels, attempt_atom}])} 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 index deee0a29279..1061556f5f6 100644 --- a/samples/client/petstore/erlang-client/src/swagger_store_api.erl +++ b/samples/client/petstore/erlang-client/src/swagger_store_api.erl @@ -9,157 +9,80 @@ %% @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. +-spec delete_order(binary()) -> ok | {error, integer()}. delete_order(OrderId) -> Method = delete, Path = ["/store/order/", OrderId, ""], - QS = lists:flatten([]), + QS = [], Headers = [], Body1 = [], Opts = [], Url = hackney_url:make_url(?BASE_URL, Path, QS), - case hackney:request(Method, Url, Headers, Body1, Opts) of - {ok, 400, RespHeaders, ClientRef} -> - case lists:keyfind(<<"Content-Type">>, 1, RespHeaders) of - - <<"application/xml", _/binary>> -> - {ok, Body} = hackney:body(ClientRef), - - jsx:decode(Body, [returns_maps, {labels, attempt_atom}]); - <<"application/json", _/binary>> -> - {ok, Body} = hackney:body(ClientRef), - - jsx:decode(Body, [returns_maps, {labels, attempt_atom}]) - end; - {ok, 404, RespHeaders, ClientRef} -> - case lists:keyfind(<<"Content-Type">>, 1, RespHeaders) of - - <<"application/xml", _/binary>> -> - {ok, Body} = hackney:body(ClientRef), - - jsx:decode(Body, [returns_maps, {labels, attempt_atom}]); - <<"application/json", _/binary>> -> - {ok, Body} = hackney:body(ClientRef), - - jsx:decode(Body, [returns_maps, {labels, attempt_atom}]) - end + {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() -> maps:map(). +-spec get_inventory() -> {ok, list(), maps:map()} | {error, string()}. get_inventory() -> Method = get, Path = ["/store/inventory"], - QS = lists:flatten([]), + 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} -> - case lists:keyfind(<<"Content-Type">>, 1, RespHeaders) of - - <<"application/json", _/binary>> -> - {ok, Body} = hackney:body(ClientRef), - - jsx:decode(Body, [returns_maps, {labels, attempt_atom}]) - end + {ok, Body} = hackney:body(ClientRef), + {ok, RespHeaders, jsx:decode(Body, [returns_maps, {labels, attempt_atom}])} 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()) -> swagger_order:swagger_order(). +-spec get_order_by_id(integer()) -> {ok, list(), swagger_order:swagger_order()} | {error, string()}. get_order_by_id(OrderId) -> Method = get, Path = ["/store/order/", OrderId, ""], - QS = lists:flatten([]), + 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} -> - case lists:keyfind(<<"Content-Type">>, 1, RespHeaders) of - - <<"application/xml", _/binary>> -> - {ok, Body} = hackney:body(ClientRef), - - jsx:decode(Body, [returns_maps, {labels, attempt_atom}]); - <<"application/json", _/binary>> -> - {ok, Body} = hackney:body(ClientRef), - - jsx:decode(Body, [returns_maps, {labels, attempt_atom}]) - end; - {ok, 400, RespHeaders, ClientRef} -> - case lists:keyfind(<<"Content-Type">>, 1, RespHeaders) of - - <<"application/xml", _/binary>> -> - {ok, Body} = hackney:body(ClientRef), - - jsx:decode(Body, [returns_maps, {labels, attempt_atom}]); - <<"application/json", _/binary>> -> - {ok, Body} = hackney:body(ClientRef), - - jsx:decode(Body, [returns_maps, {labels, attempt_atom}]) - end; - {ok, 404, RespHeaders, ClientRef} -> - case lists:keyfind(<<"Content-Type">>, 1, RespHeaders) of - - <<"application/xml", _/binary>> -> - {ok, Body} = hackney:body(ClientRef), - - jsx:decode(Body, [returns_maps, {labels, attempt_atom}]); - <<"application/json", _/binary>> -> - {ok, Body} = hackney:body(ClientRef), - - jsx:decode(Body, [returns_maps, {labels, attempt_atom}]) - end + {ok, Body} = hackney:body(ClientRef), + {ok, RespHeaders, jsx:decode(Body, [returns_maps, {labels, attempt_atom}])}; + {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()) -> swagger_order:swagger_order(). +-spec place_order(swagger_order:swagger_order()) -> {ok, list(), swagger_order:swagger_order()} | {error, string()}. place_order(Body) -> Method = post, Path = ["/store/order"], - QS = lists:flatten([]), + 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} -> - case lists:keyfind(<<"Content-Type">>, 1, RespHeaders) of - - <<"application/xml", _/binary>> -> - {ok, Body} = hackney:body(ClientRef), - - jsx:decode(Body, [returns_maps, {labels, attempt_atom}]); - <<"application/json", _/binary>> -> - {ok, Body} = hackney:body(ClientRef), - - jsx:decode(Body, [returns_maps, {labels, attempt_atom}]) - end; - {ok, 400, RespHeaders, ClientRef} -> - case lists:keyfind(<<"Content-Type">>, 1, RespHeaders) of - - <<"application/xml", _/binary>> -> - {ok, Body} = hackney:body(ClientRef), - - jsx:decode(Body, [returns_maps, {labels, attempt_atom}]); - <<"application/json", _/binary>> -> - {ok, Body} = hackney:body(ClientRef), - - jsx:decode(Body, [returns_maps, {labels, attempt_atom}]) - end + {ok, Body} = hackney:body(ClientRef), + {ok, RespHeaders, jsx:decode(Body, [returns_maps, {labels, attempt_atom}])}; + {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 index 12770e465ed..fe2a84d78a8 100644 --- a/samples/client/petstore/erlang-client/src/swagger_user_api.erl +++ b/samples/client/petstore/erlang-client/src/swagger_user_api.erl @@ -13,179 +13,101 @@ %% @doc Create user %% This can only be done by the logged in user. --spec create_user(swagger_user:swagger_user()) -> ok. +-spec create_user(swagger_user:swagger_user()) -> ok | {error, integer()}. create_user(Body) -> Method = post, Path = ["/user"], - QS = lists:flatten([]), + QS = [], Headers = [], Body1 = Body, Opts = [], Url = hackney_url:make_url(?BASE_URL, Path, QS), - case hackney:request(Method, Url, Headers, Body1, Opts) of - {ok, 0, RespHeaders, ClientRef} -> - case lists:keyfind(<<"Content-Type">>, 1, RespHeaders) of - - <<"application/xml", _/binary>> -> - {ok, Body} = hackney:body(ClientRef), - - jsx:decode(Body, [returns_maps, {labels, attempt_atom}]); - <<"application/json", _/binary>> -> - {ok, Body} = hackney:body(ClientRef), - - jsx:decode(Body, [returns_maps, {labels, attempt_atom}]) - end + {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. +-spec create_users_with_array_input(list()) -> ok | {error, integer()}. create_users_with_array_input(Body) -> Method = post, Path = ["/user/createWithArray"], - QS = lists:flatten([]), + QS = [], Headers = [], Body1 = Body, Opts = [], Url = hackney_url:make_url(?BASE_URL, Path, QS), - case hackney:request(Method, Url, Headers, Body1, Opts) of - {ok, 0, RespHeaders, ClientRef} -> - case lists:keyfind(<<"Content-Type">>, 1, RespHeaders) of - - <<"application/xml", _/binary>> -> - {ok, Body} = hackney:body(ClientRef), - - jsx:decode(Body, [returns_maps, {labels, attempt_atom}]); - <<"application/json", _/binary>> -> - {ok, Body} = hackney:body(ClientRef), - - jsx:decode(Body, [returns_maps, {labels, attempt_atom}]) - end + {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. +-spec create_users_with_list_input(list()) -> ok | {error, integer()}. create_users_with_list_input(Body) -> Method = post, Path = ["/user/createWithList"], - QS = lists:flatten([]), + QS = [], Headers = [], Body1 = Body, Opts = [], Url = hackney_url:make_url(?BASE_URL, Path, QS), - case hackney:request(Method, Url, Headers, Body1, Opts) of - {ok, 0, RespHeaders, ClientRef} -> - case lists:keyfind(<<"Content-Type">>, 1, RespHeaders) of - - <<"application/xml", _/binary>> -> - {ok, Body} = hackney:body(ClientRef), - - jsx:decode(Body, [returns_maps, {labels, attempt_atom}]); - <<"application/json", _/binary>> -> - {ok, Body} = hackney:body(ClientRef), - - jsx:decode(Body, [returns_maps, {labels, attempt_atom}]) - end + {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. +-spec delete_user(binary()) -> ok | {error, integer()}. delete_user(Username) -> Method = delete, Path = ["/user/", Username, ""], - QS = lists:flatten([]), + QS = [], Headers = [], Body1 = [], Opts = [], Url = hackney_url:make_url(?BASE_URL, Path, QS), - case hackney:request(Method, Url, Headers, Body1, Opts) of - {ok, 400, RespHeaders, ClientRef} -> - case lists:keyfind(<<"Content-Type">>, 1, RespHeaders) of - - <<"application/xml", _/binary>> -> - {ok, Body} = hackney:body(ClientRef), - - jsx:decode(Body, [returns_maps, {labels, attempt_atom}]); - <<"application/json", _/binary>> -> - {ok, Body} = hackney:body(ClientRef), - - jsx:decode(Body, [returns_maps, {labels, attempt_atom}]) - end; - {ok, 404, RespHeaders, ClientRef} -> - case lists:keyfind(<<"Content-Type">>, 1, RespHeaders) of - - <<"application/xml", _/binary>> -> - {ok, Body} = hackney:body(ClientRef), - - jsx:decode(Body, [returns_maps, {labels, attempt_atom}]); - <<"application/json", _/binary>> -> - {ok, Body} = hackney:body(ClientRef), - - jsx:decode(Body, [returns_maps, {labels, attempt_atom}]) - end + {ok, 200, _RespHeaders, _ClientRef} -> + ok; + {ok, Status, _RespHeaders, _ClientRef} -> + {error, Status} end. %% @doc Get user by user name --spec get_user_by_name(binary()) -> swagger_user:swagger_user(). +-spec get_user_by_name(binary()) -> {ok, list(), swagger_user:swagger_user()} | {error, string()}. get_user_by_name(Username) -> Method = get, Path = ["/user/", Username, ""], - QS = lists:flatten([]), + 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} -> - case lists:keyfind(<<"Content-Type">>, 1, RespHeaders) of - - <<"application/xml", _/binary>> -> - {ok, Body} = hackney:body(ClientRef), - - jsx:decode(Body, [returns_maps, {labels, attempt_atom}]); - <<"application/json", _/binary>> -> - {ok, Body} = hackney:body(ClientRef), - - jsx:decode(Body, [returns_maps, {labels, attempt_atom}]) - end; - {ok, 400, RespHeaders, ClientRef} -> - case lists:keyfind(<<"Content-Type">>, 1, RespHeaders) of - - <<"application/xml", _/binary>> -> - {ok, Body} = hackney:body(ClientRef), - - jsx:decode(Body, [returns_maps, {labels, attempt_atom}]); - <<"application/json", _/binary>> -> - {ok, Body} = hackney:body(ClientRef), - - jsx:decode(Body, [returns_maps, {labels, attempt_atom}]) - end; - {ok, 404, RespHeaders, ClientRef} -> - case lists:keyfind(<<"Content-Type">>, 1, RespHeaders) of - - <<"application/xml", _/binary>> -> - {ok, Body} = hackney:body(ClientRef), - - jsx:decode(Body, [returns_maps, {labels, attempt_atom}]); - <<"application/json", _/binary>> -> - {ok, Body} = hackney:body(ClientRef), - - jsx:decode(Body, [returns_maps, {labels, attempt_atom}]) - end + {ok, Body} = hackney:body(ClientRef), + {ok, RespHeaders, jsx:decode(Body, [returns_maps, {labels, attempt_atom}])}; + {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()) -> binary(). +-spec login_user(binary(), binary()) -> {ok, list(), binary()} | {error, string()}. login_user(Username, Password) -> Method = get, Path = ["/user/login"], @@ -195,99 +117,49 @@ login_user(Username, Password) -> Opts = [], Url = hackney_url:make_url(?BASE_URL, Path, QS), - case hackney:request(Method, Url, Headers, Body1, Opts) of {ok, 200, RespHeaders, ClientRef} -> - case lists:keyfind(<<"Content-Type">>, 1, RespHeaders) of - - <<"application/xml", _/binary>> -> - {ok, Body} = hackney:body(ClientRef), - - jsx:decode(Body, [returns_maps, {labels, attempt_atom}]); - <<"application/json", _/binary>> -> - {ok, Body} = hackney:body(ClientRef), - - jsx:decode(Body, [returns_maps, {labels, attempt_atom}]) - end; - {ok, 400, RespHeaders, ClientRef} -> - case lists:keyfind(<<"Content-Type">>, 1, RespHeaders) of - - <<"application/xml", _/binary>> -> - {ok, Body} = hackney:body(ClientRef), - - jsx:decode(Body, [returns_maps, {labels, attempt_atom}]); - <<"application/json", _/binary>> -> - {ok, Body} = hackney:body(ClientRef), - - jsx:decode(Body, [returns_maps, {labels, attempt_atom}]) - end + {ok, Body} = hackney:body(ClientRef), + {ok, RespHeaders, jsx:decode(Body, [returns_maps, {labels, attempt_atom}])}; + {ok, 400, _RespHeaders, _ClientRef} -> + {error, "Invalid username/password supplied"} end. %% @doc Logs out current logged in user session --spec logout_user() -> ok. +-spec logout_user() -> ok | {error, integer()}. logout_user() -> Method = get, Path = ["/user/logout"], - QS = lists:flatten([]), + QS = [], Headers = [], Body1 = [], Opts = [], Url = hackney_url:make_url(?BASE_URL, Path, QS), - case hackney:request(Method, Url, Headers, Body1, Opts) of - {ok, 0, RespHeaders, ClientRef} -> - case lists:keyfind(<<"Content-Type">>, 1, RespHeaders) of - - <<"application/xml", _/binary>> -> - {ok, Body} = hackney:body(ClientRef), - - jsx:decode(Body, [returns_maps, {labels, attempt_atom}]); - <<"application/json", _/binary>> -> - {ok, Body} = hackney:body(ClientRef), - - jsx:decode(Body, [returns_maps, {labels, attempt_atom}]) - end + {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. +-spec update_user(binary(), swagger_user:swagger_user()) -> ok | {error, integer()}. update_user(Username, Body) -> Method = put, Path = ["/user/", Username, ""], - QS = lists:flatten([]), + QS = [], Headers = [], Body1 = Body, Opts = [], Url = hackney_url:make_url(?BASE_URL, Path, QS), - case hackney:request(Method, Url, Headers, Body1, Opts) of - {ok, 400, RespHeaders, ClientRef} -> - case lists:keyfind(<<"Content-Type">>, 1, RespHeaders) of - - <<"application/xml", _/binary>> -> - {ok, Body} = hackney:body(ClientRef), - - jsx:decode(Body, [returns_maps, {labels, attempt_atom}]); - <<"application/json", _/binary>> -> - {ok, Body} = hackney:body(ClientRef), - - jsx:decode(Body, [returns_maps, {labels, attempt_atom}]) - end; - {ok, 404, RespHeaders, ClientRef} -> - case lists:keyfind(<<"Content-Type">>, 1, RespHeaders) of - - <<"application/xml", _/binary>> -> - {ok, Body} = hackney:body(ClientRef), - - jsx:decode(Body, [returns_maps, {labels, attempt_atom}]); - <<"application/json", _/binary>> -> - {ok, Body} = hackney:body(ClientRef), - - jsx:decode(Body, [returns_maps, {labels, attempt_atom}]) - end + {ok, 200, _RespHeaders, _ClientRef} -> + ok; + {ok, Status, _RespHeaders, _ClientRef} -> + {error, Status} end.