diff --git a/docs/generators.md b/docs/generators.md
index 1fe95d2ad93..6cf92be1945 100644
--- a/docs/generators.md
+++ b/docs/generators.md
@@ -89,6 +89,7 @@ The following generators are available:
* [cpp-restbed-server-deprecated](generators/cpp-restbed-server-deprecated.md)
* [csharp-functions](generators/csharp-functions.md)
* [erlang-server](generators/erlang-server.md)
+* [erlang-server-deprecated (deprecated)](generators/erlang-server-deprecated.md)
* [fsharp-functions (beta)](generators/fsharp-functions.md)
* [fsharp-giraffe-server (beta)](generators/fsharp-giraffe-server.md)
* [go-echo-server (beta)](generators/go-echo-server.md)
diff --git a/docs/generators/erlang-server-deprecated.md b/docs/generators/erlang-server-deprecated.md
new file mode 100644
index 00000000000..b3f96ea6158
--- /dev/null
+++ b/docs/generators/erlang-server-deprecated.md
@@ -0,0 +1,190 @@
+---
+title: Documentation for the erlang-server-deprecated Generator
+---
+
+## METADATA
+
+| Property | Value | Notes |
+| -------- | ----- | ----- |
+| generator name | erlang-server-deprecated | pass this to the generate command after -g |
+| generator stability | DEPRECATED | |
+| generator type | SERVER | |
+| generator language | Erlang | |
+| generator default templating engine | mustache | |
+| helpTxt | Generates an Erlang server library (deprecated) using OpenAPI Generator (https://openapi-generator.tech). By default, it will also generate service classes, which can be disabled with the `-Dnoservice` environment variable. | |
+
+## CONFIG OPTIONS
+These options may be applied as additional-properties (cli) or configOptions (plugins). Refer to [configuration docs](https://openapi-generator.tech/docs/configuration) for more details.
+
+| Option | Description | Values | Default |
+| ------ | ----------- | ------ | ------- |
+|openAPISpecName|Openapi Spec Name.| |openapi|
+|packageName|Erlang package name (convention: lowercase).| |openapi|
+
+## IMPORT MAPPING
+
+| Type/Alias | Imports |
+| ---------- | ------- |
+
+
+## INSTANTIATION TYPES
+
+| Type/Alias | Instantiated By |
+| ---------- | --------------- |
+
+
+## LANGUAGE PRIMITIVES
+
+
+
+## RESERVED WORDS
+
+
+- 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
+
+
+## FEATURE SET
+
+
+### Client Modification Feature
+| Name | Supported | Defined By |
+| ---- | --------- | ---------- |
+|BasePath|✗|ToolingExtension
+|Authorizations|✗|ToolingExtension
+|UserAgent|✗|ToolingExtension
+|MockServer|✗|ToolingExtension
+
+### Data Type Feature
+| Name | Supported | Defined By |
+| ---- | --------- | ---------- |
+|Custom|✗|OAS2,OAS3
+|Int32|✓|OAS2,OAS3
+|Int64|✓|OAS2,OAS3
+|Float|✓|OAS2,OAS3
+|Double|✓|OAS2,OAS3
+|Decimal|✓|ToolingExtension
+|String|✓|OAS2,OAS3
+|Byte|✓|OAS2,OAS3
+|Binary|✓|OAS2,OAS3
+|Boolean|✓|OAS2,OAS3
+|Date|✓|OAS2,OAS3
+|DateTime|✓|OAS2,OAS3
+|Password|✓|OAS2,OAS3
+|File|✓|OAS2
+|Uuid|✗|
+|Array|✓|OAS2,OAS3
+|Null|✗|OAS3
+|AnyType|✗|OAS2,OAS3
+|Object|✓|OAS2,OAS3
+|Maps|✓|ToolingExtension
+|CollectionFormat|✓|OAS2
+|CollectionFormatMulti|✓|OAS2
+|Enum|✓|OAS2,OAS3
+|ArrayOfEnum|✓|ToolingExtension
+|ArrayOfModel|✓|ToolingExtension
+|ArrayOfCollectionOfPrimitives|✓|ToolingExtension
+|ArrayOfCollectionOfModel|✓|ToolingExtension
+|ArrayOfCollectionOfEnum|✓|ToolingExtension
+|MapOfEnum|✓|ToolingExtension
+|MapOfModel|✓|ToolingExtension
+|MapOfCollectionOfPrimitives|✓|ToolingExtension
+|MapOfCollectionOfModel|✓|ToolingExtension
+|MapOfCollectionOfEnum|✓|ToolingExtension
+
+### Documentation Feature
+| Name | Supported | Defined By |
+| ---- | --------- | ---------- |
+|Readme|✓|ToolingExtension
+|Model|✓|ToolingExtension
+|Api|✓|ToolingExtension
+
+### Global Feature
+| Name | Supported | Defined By |
+| ---- | --------- | ---------- |
+|Host|✓|OAS2,OAS3
+|BasePath|✓|OAS2,OAS3
+|Info|✓|OAS2,OAS3
+|Schemes|✗|OAS2,OAS3
+|PartialSchemes|✓|OAS2,OAS3
+|Consumes|✓|OAS2
+|Produces|✓|OAS2
+|ExternalDocumentation|✓|OAS2,OAS3
+|Examples|✓|OAS2,OAS3
+|XMLStructureDefinitions|✗|OAS2,OAS3
+|MultiServer|✗|OAS3
+|ParameterizedServer|✗|OAS3
+|ParameterStyling|✗|OAS3
+|Callbacks|✗|OAS3
+|LinkObjects|✗|OAS3
+
+### Parameter Feature
+| Name | Supported | Defined By |
+| ---- | --------- | ---------- |
+|Path|✓|OAS2,OAS3
+|Query|✓|OAS2,OAS3
+|Header|✓|OAS2,OAS3
+|Body|✓|OAS2
+|FormUnencoded|✓|OAS2
+|FormMultipart|✓|OAS2
+|Cookie|✗|OAS3
+
+### Schema Support Feature
+| Name | Supported | Defined By |
+| ---- | --------- | ---------- |
+|Simple|✓|OAS2,OAS3
+|Composite|✓|OAS2,OAS3
+|Polymorphism|✗|OAS2,OAS3
+|Union|✗|OAS3
+|allOf|✗|OAS2,OAS3
+|anyOf|✗|OAS3
+|oneOf|✗|OAS3
+|not|✗|OAS3
+
+### Security Feature
+| Name | Supported | Defined By |
+| ---- | --------- | ---------- |
+|BasicAuth|✗|OAS2,OAS3
+|ApiKey|✓|OAS2,OAS3
+|OpenIDConnect|✗|OAS3
+|BearerToken|✗|OAS3
+|OAuth2_Implicit|✓|OAS2,OAS3
+|OAuth2_Password|✗|OAS2,OAS3
+|OAuth2_ClientCredentials|✗|OAS2,OAS3
+|OAuth2_AuthorizationCode|✗|OAS2,OAS3
+|SignatureAuth|✗|OAS3
+|AWSV4Signature|✗|ToolingExtension
+
+### Wire Format Feature
+| Name | Supported | Defined By |
+| ---- | --------- | ---------- |
+|JSON|✓|OAS2,OAS3
+|XML|✗|OAS2,OAS3
+|PROTOBUF|✗|ToolingExtension
+|Custom|✗|OAS2,OAS3
diff --git a/modules/openapi-generator/src/main/java/org/openapitools/codegen/languages/ErlangServerDeprecatedCodegen.java b/modules/openapi-generator/src/main/java/org/openapitools/codegen/languages/ErlangServerDeprecatedCodegen.java
new file mode 100644
index 00000000000..650951028cc
--- /dev/null
+++ b/modules/openapi-generator/src/main/java/org/openapitools/codegen/languages/ErlangServerDeprecatedCodegen.java
@@ -0,0 +1,337 @@
+/*
+ * Copyright 2018 OpenAPI-Generator Contributors (https://openapi-generator.tech)
+ * Copyright 2018 SmartBear Software
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * https://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.openapitools.codegen.languages;
+
+import lombok.Setter;
+import org.openapitools.codegen.*;
+import org.openapitools.codegen.meta.features.*;
+import org.openapitools.codegen.model.ModelMap;
+import org.openapitools.codegen.model.OperationMap;
+import org.openapitools.codegen.model.OperationsMap;
+import org.openapitools.codegen.meta.features.*;
+import org.openapitools.codegen.meta.GeneratorMetadata;
+import org.openapitools.codegen.meta.Stability;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.io.File;
+import java.util.Arrays;
+import java.util.EnumSet;
+import java.util.List;
+import java.util.Map;
+
+import static org.openapitools.codegen.utils.StringUtils.camelize;
+import static org.openapitools.codegen.utils.StringUtils.underscore;
+
+public class ErlangServerDeprecatedCodegen extends DefaultCodegen implements CodegenConfig {
+
+ private final Logger LOGGER = LoggerFactory.getLogger(ErlangServerDeprecatedCodegen.class);
+
+ protected String apiVersion = "1.0.0";
+ protected String apiPath = "src";
+ @Setter protected String packageName = "openapi";
+ @Setter protected String openApiSpecName = "openapi";
+
+ public ErlangServerDeprecatedCodegen() {
+ super();
+
+ generatorMetadata = GeneratorMetadata.newBuilder(generatorMetadata).stability(Stability.DEPRECATED).build();
+
+ modifyFeatureSet(features -> features
+ .includeDocumentationFeatures(DocumentationFeature.Readme)
+ .wireFormatFeatures(EnumSet.of(WireFormatFeature.JSON))
+ .securityFeatures(EnumSet.of(
+ SecurityFeature.ApiKey,
+ SecurityFeature.OAuth2_Implicit
+ ))
+ .excludeGlobalFeatures(
+ GlobalFeature.XMLStructureDefinitions,
+ GlobalFeature.Callbacks,
+ GlobalFeature.LinkObjects,
+ GlobalFeature.ParameterStyling
+ )
+ .excludeSchemaSupportFeatures(
+ SchemaSupportFeature.Polymorphism
+ )
+ .excludeParameterFeatures(
+ ParameterFeature.Cookie
+ )
+ );
+
+ // set the output folder here
+ outputFolder = "generated-code/erlang-server";
+
+ /**
+ * Models. You can write model files using the modelTemplateFiles map.
+ * if you want to create one template for file, you can do so here.
+ * for multiple files for model, just put another entry in the `modelTemplateFiles` with
+ * a different extension
+ */
+ modelTemplateFiles.clear();
+
+ /**
+ * Api classes. You can write classes for each Api file with the apiTemplateFiles map.
+ * as with models, add multiple entries with different extensions for multiple files per
+ * class
+ */
+ apiTemplateFiles.put(
+ "handler.mustache", // the template to use
+ ".erl"); // the extension for each file to write
+
+ /**
+ * Template Location. This is the location which templates will be read from. The generator
+ * will use the resource stream to attempt to read the templates.
+ */
+ embeddedTemplateDir = templateDir = "erlang-server-deprecated";
+
+ /**
+ * Reserved words. Override this with reserved words specific to your language
+ */
+ 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("uri", "binary");
+ typeMapping.put("password", "binary");
+
+ cliOptions.clear();
+ cliOptions.add(new CliOption(CodegenConstants.PACKAGE_NAME, "Erlang package name (convention: lowercase).")
+ .defaultValue(this.packageName));
+
+ cliOptions.add(new CliOption(CodegenConstants.OPEN_API_SPEC_NAME, "Openapi Spec Name.")
+ .defaultValue(this.openApiSpecName));
+ }
+
+ @Override
+ public void processOpts() {
+ super.processOpts();
+
+ if (additionalProperties.containsKey(CodegenConstants.PACKAGE_NAME)) {
+ setPackageName((String) additionalProperties.get(CodegenConstants.PACKAGE_NAME));
+ } else {
+ additionalProperties.put(CodegenConstants.PACKAGE_NAME, packageName);
+ }
+
+ if (additionalProperties.containsKey(CodegenConstants.OPEN_API_SPEC_NAME)) {
+ setOpenApiSpecName((String) additionalProperties.get(CodegenConstants.OPEN_API_SPEC_NAME));
+ } else {
+ additionalProperties.put(CodegenConstants.OPEN_API_SPEC_NAME, openApiSpecName);
+ }
+
+ /**
+ * Additional Properties. These values can be passed to the templates and
+ * are available in models, apis, and supporting files
+ */
+ additionalProperties.put("apiVersion", apiVersion);
+ additionalProperties.put("apiPath", apiPath);
+ /**
+ * Supporting Files. You can write single files for the generator with the
+ * entire object tree available. If the input file has a suffix of `.mustache
+ * it will be processed by the template engine. Otherwise, it will be copied
+ */
+ 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("router.mustache", "", toSourceFilePath("router", "erl")));
+ supportingFiles.add(new SupportingFile("api.mustache", "", toSourceFilePath("api", "erl")));
+ supportingFiles.add(new SupportingFile("server.mustache", "", toSourceFilePath("server", "erl")));
+ supportingFiles.add(new SupportingFile("utils.mustache", "", toSourceFilePath("utils", "erl")));
+ supportingFiles.add(new SupportingFile("auth.mustache", "", toSourceFilePath("auth", "erl")));
+ supportingFiles.add(new SupportingFile("openapi.mustache", "", toPrivFilePath(this.openApiSpecName, "json")));
+ supportingFiles.add(new SupportingFile("default_logic_handler.mustache", "", toSourceFilePath("default_logic_handler", "erl")));
+ supportingFiles.add(new SupportingFile("logic_handler.mustache", "", toSourceFilePath("logic_handler", "erl")));
+ supportingFiles.add(new SupportingFile("README.mustache", "", "README.md")
+ .doNotOverwrite());
+ }
+
+ @Override
+ public String apiPackage() {
+ return apiPath;
+ }
+
+ /**
+ * Configures the type of generator.
+ *
+ * @return the CodegenType for this generator
+ * @see org.openapitools.codegen.CodegenType
+ */
+ @Override
+ public CodegenType getTag() {
+ return CodegenType.SERVER;
+ }
+
+ /**
+ * Configures a friendly name for the generator. This will be used by the generator
+ * to select the library with the -g flag.
+ *
+ * @return the friendly name for the generator
+ */
+ @Override
+ public String getName() {
+ return "erlang-server-deprecated";
+ }
+
+ /**
+ * Returns human-friendly help for the generator. Provide the consumer with help
+ * tips, parameters here
+ *
+ * @return A string value for the help message
+ */
+ @Override
+ public String getHelp() {
+ return "Generates an Erlang server library (deprecated) using OpenAPI Generator (https://openapi-generator.tech). By default, " +
+ "it will also generate service classes, which can be disabled with the `-Dnoservice` environment variable.";
+ }
+
+ @Override
+ public String toApiName(String name) {
+ if (name.length() == 0) {
+ return this.packageName + "_default_handler";
+ }
+ return this.packageName + "_" + underscore(name) + "_handler";
+ }
+
+ /**
+ * Escapes a reserved word as defined in the `reservedWords` array. Handle escaping
+ * those terms here. This logic is only called if a variable matches the reserved words
+ *
+ * @return the escaped term
+ */
+ @Override
+ public String escapeReservedWord(String name) {
+ if (this.reservedWordsMappings().containsKey(name)) {
+ return this.reservedWordsMappings().get(name);
+ }
+ return "_" + name;
+ }
+
+ /**
+ * Location to write api files. You can use the apiPackage() as defined when the class is
+ * instantiated
+ */
+ @Override
+ public String apiFileFolder() {
+ return outputFolder + File.separator + apiPackage().replace('.', File.separatorChar);
+ }
+
+ @Override
+ public String toModelName(String name) {
+ return camelize(toModelFilename(name));
+ }
+
+ @Override
+ public String toOperationId(String operationId) {
+ // method name cannot use reserved keyword, e.g. return
+ if (isReservedWord(operationId)) {
+ LOGGER.warn("{} (reserved word) cannot be used as method name. Renamed to {}", operationId, camelize(sanitizeName("call_" + operationId)));
+ operationId = "call_" + operationId;
+ }
+
+ return camelize(operationId);
+ }
+
+ @Override
+ public String toApiFilename(String name) {
+ return toHandlerName(name);
+ }
+
+ @Override
+ public OperationsMap postProcessOperationsWithModels(OperationsMap objs, List allModels) {
+ OperationMap operations = objs.getOperations();
+ List operationList = operations.getOperation();
+ for (CodegenOperation op : operationList) {
+ if (op.path != null) {
+ op.path = op.path.replaceAll("\\{(.*?)\\}", ":$1");
+ }
+ }
+ return objs;
+ }
+
+ @Override
+ public Map postProcessSupportingFileData(Map objs) {
+ generateJSONSpecFile(objs);
+ return super.postProcessSupportingFileData(objs);
+ }
+
+ protected String toHandlerName(String name) {
+ return toModuleName(name) + "_handler";
+ }
+
+ protected String toModuleName(String name) {
+ return this.packageName + "_" + underscore(name.replaceAll("-", "_"));
+ }
+
+ protected String toSourceFilePath(String name, String extension) {
+ return "src" + File.separator + toModuleName(name) + "." + extension;
+ }
+
+ protected String toIncludeFilePath(String name, String extension) {
+ return "include" + File.separator + toModuleName(name) + "." + extension;
+ }
+
+ protected String toPrivFilePath(String name, String extension) {
+ return "priv" + File.separator + name + "." + extension;
+ }
+
+ @Override
+ public String escapeQuotationMark(String input) {
+ // remove ' to avoid code injection
+ return input.replace("'", "");
+ }
+
+ @Override
+ public String escapeUnsafeCharacters(String input) {
+ // ref: http://stackoverflow.com/a/30421295/677735
+ return input.replace("-ifdef", "- if def").replace("-endif", "- end if");
+ }
+
+ @Override
+ public String addRegularExpressionDelimiter(String pattern) {
+ return pattern;
+ }
+
+ @Override
+ public GeneratorLanguage generatorLanguage() { return GeneratorLanguage.ERLANG; }
+}
diff --git a/modules/openapi-generator/src/main/resources/META-INF/services/org.openapitools.codegen.CodegenConfig b/modules/openapi-generator/src/main/resources/META-INF/services/org.openapitools.codegen.CodegenConfig
index ba2d139af98..00a51f289ab 100644
--- a/modules/openapi-generator/src/main/resources/META-INF/services/org.openapitools.codegen.CodegenConfig
+++ b/modules/openapi-generator/src/main/resources/META-INF/services/org.openapitools.codegen.CodegenConfig
@@ -30,6 +30,7 @@ org.openapitools.codegen.languages.ElmClientCodegen
org.openapitools.codegen.languages.ErlangClientCodegen
org.openapitools.codegen.languages.ErlangProperCodegen
org.openapitools.codegen.languages.ErlangServerCodegen
+org.openapitools.codegen.languages.ErlangServerDeprecatedCodegen
org.openapitools.codegen.languages.FsharpFunctionsServerCodegen
org.openapitools.codegen.languages.FsharpGiraffeServerCodegen
org.openapitools.codegen.languages.GoClientCodegen
diff --git a/modules/openapi-generator/src/main/resources/erlang-server-deprecated/README.mustache b/modules/openapi-generator/src/main/resources/erlang-server-deprecated/README.mustache
new file mode 100644
index 00000000000..5d36ca07576
--- /dev/null
+++ b/modules/openapi-generator/src/main/resources/erlang-server-deprecated/README.mustache
@@ -0,0 +1,57 @@
+# OpenAPI server library for Erlang
+
+## Overview
+
+An Erlang server stub generated by [OpenAPI Generator](https://openapi-generator.tech) given an OpenAPI spec.
+
+Dependency: [Cowboy](https://github.com/ninenines/cowboy)
+
+## Prerequisites
+
+TODO
+
+## Getting started
+Use erlang-server with erlang.mk
+
+ 1, Create an application by using erlang.mk
+ $ mkdir http_server
+ $ cd http_server
+ $ wget https://erlang.mk/erlang.mk
+ $ make -f erlang.mk bootstrap bootstrap-rel
+ $ make run
+
+ 2, Modify the Makefile in the http_server directory to the following to introduce the dependency library:
+ PROJECT = http_server
+ PROJECT_DESCRIPTION = New project
+ PROJECT_VERSION = 0.1.0
+
+ DEPS = cowboy jesse jsx
+ dep_cowboy_commit = 2.5.0
+ dep_jesse_commit = 1.5.2
+ dep_jsx_commit = 2.9.0
+ DEP_PLUGINS = cowboy jesse jsx
+
+ PACKAGES += rfc3339
+ pkg_rfc3339_name = rfc3339
+ pkg_rfc3339_description = an erlang/elixir rfc3339 lib
+ pkg_rfc3339_homepage = https://github.com/talentdeficit/rfc3339
+ pkg_rfc3339_fetch = git
+ pkg_rfc3339_repo = https://github.com/talentdeficit/rfc3339
+ pkg_rfc3339_commit = master
+
+ include erlang.mk
+
+ 3, Generate erlang-server project using openapi-generator
+ https://github.com/OpenAPITools/openapi-generator#2---getting-started
+
+ 4, Copy erlang-server file to http_server project,Don't forget the 'priv' folder.
+
+ 5, Start in the http_server project:
+ 1, Introduce the following line in the http_server_app:start(_Type, _Args) function
+ openapi_server:start(http_server, #{ip=>{127,0,0,1}, port=>8080, net_opts=>[]})
+ 2, Compilation http_server project
+ $ make
+ 3, Start erlang virtual machine
+ $erl -pa ./deps/cowboy/ebin -pa ./deps/cowlib/ebin -pa ./deps/ranch/ebin -pa ./deps/jsx/ebin -pa ./deps/jesse/ebin -pa ./deps/rfc3339/ebin -pa ./ebin
+ 4, Start project
+ application:ensure_all_started(http_server).
diff --git a/modules/openapi-generator/src/main/resources/erlang-server-deprecated/api.mustache b/modules/openapi-generator/src/main/resources/erlang-server-deprecated/api.mustache
new file mode 100644
index 00000000000..b97e4a2c5ec
--- /dev/null
+++ b/modules/openapi-generator/src/main/resources/erlang-server-deprecated/api.mustache
@@ -0,0 +1,363 @@
+-module({{packageName}}_api).
+
+-export([request_params/1]).
+-export([request_param_info/2]).
+-export([populate_request/3]).
+-export([validate_response/4]).
+%% exported to silence openapi complains
+-export([get_value/3, validate_response_body/4]).
+
+-type operation_id() :: atom().
+-type request_param() :: atom().
+
+-export_type([operation_id/0]).
+
+-spec request_params(OperationID :: operation_id()) -> [Param :: request_param()].
+{{#apiInfo}}{{#apis}}
+{{#operations}}{{#operation}}
+request_params('{{operationId}}') ->
+ [{{#allParams}}{{^isBodyParam}}
+ '{{baseName}}'{{/isBodyParam}}{{#isBodyParam}}
+ '{{dataType}}'{{/isBodyParam}}{{^-last}},{{/-last}}{{/allParams}}
+ ];
+{{/operation}}{{/operations}}{{/apis}}{{/apiInfo}}
+request_params(_) ->
+ error(unknown_operation).
+
+-type rule() ::
+ {type, 'binary'} |
+ {type, 'integer'} |
+ {type, 'float'} |
+ {type, 'binary'} |
+ {type, 'boolean'} |
+ {type, 'date'} |
+ {type, 'datetime'} |
+ {enum, [atom()]} |
+ {max, Max :: number()} |
+ {exclusive_max, Max :: number()} |
+ {min, Min :: number()} |
+ {exclusive_min, Min :: number()} |
+ {max_length, MaxLength :: integer()} |
+ {min_length, MaxLength :: integer()} |
+ {pattern, Pattern :: string()} |
+ schema |
+ required |
+ not_required.
+
+-spec request_param_info(OperationID :: operation_id(), Name :: request_param()) -> #{
+ source => qs_val | binding | header | body,
+ rules => [rule()]
+}.
+
+{{#apiInfo}}{{#apis}}
+{{#operations}}{{#operation}}{{#allParams}}
+request_param_info('{{operationId}}', {{^isBodyParam}}'{{baseName}}'{{/isBodyParam}}{{#isBodyParam}}'{{dataType}}'{{/isBodyParam}}) ->
+ #{
+ source => {{#isQueryParam}}qs_val{{/isQueryParam}} {{#isPathParam}}binding{{/isPathParam}} {{#isHeaderParam}}header{{/isHeaderParam}}{{#isBodyParam}}body{{/isBodyParam}}{{#isFormParam}}body{{/isFormParam}},
+ rules => [{{#isString}}
+ {type, 'binary'},{{/isString}}{{#isInteger}}
+ {type, 'integer'},{{/isInteger}}{{#isLong}}
+ {type, 'integer'},{{/isLong}}{{#isFloat}}
+ {type, 'float'},{{/isFloat}}{{#isDouble}}
+ {type, 'float'},{{/isDouble}}{{#isByteArray}}
+ {type, 'binary'},{{/isByteArray}}{{#isBinary}}
+ {type, 'binary'},{{/isBinary}}{{#isBoolean}}
+ {type, 'boolean'},{{/isBoolean}}{{#isDate}}
+ {type, 'date'},{{/isDate}}{{#isDateTime}}
+ {type, 'datetime'},{{/isDateTime}}{{#isEnum}}
+ {enum, [{{#allowableValues}}{{#values}}'{{.}}'{{^-last}}, {{/-last}}{{/values}}{{/allowableValues}}] },{{/isEnum}}{{#maximum}}
+ {max, {{maximum}} }, {{/maximum}}{{#exclusiveMaximum}}
+ {exclusive_max, {{exclusiveMaximum}} },{{/exclusiveMaximum}}{{#minimum}}
+ {min, {{minimum}} },{{/minimum}}{{#exclusiveMinimum}}
+ {exclusive_min, {{exclusiveMinimum}} },{{/exclusiveMinimum}}{{#maxLength}}
+ {max_length, {{maxLength}} },{{/maxLength}}{{#minLength}}
+ {min_length, {{minLength}} },{{/minLength}}{{#pattern}}
+ {pattern, "{{{pattern}}}" },{{/pattern}}{{#isBodyParam}}
+ schema,{{/isBodyParam}}{{#required}}
+ required{{/required}}{{^required}}
+ not_required{{/required}}
+ ]
+ };
+{{/allParams}}{{/operation}}{{/operations}}{{/apis}}{{/apiInfo}}
+request_param_info(OperationID, Name) ->
+ error({unknown_param, OperationID, Name}).
+
+-spec populate_request(
+ OperationID :: operation_id(),
+ Req :: cowboy_req:req(),
+ ValidatorState :: jesse_state:state()
+) ->
+ {ok, Model :: #{}, Req :: cowboy_req:req()} |
+ {error, Reason :: any(), Req :: cowboy_req:req()}.
+
+populate_request(OperationID, Req, ValidatorState) ->
+ Params = request_params(OperationID),
+ populate_request_params(OperationID, Params, Req, ValidatorState, #{}).
+
+populate_request_params(_, [], Req, _, Model) ->
+ {ok, Model, Req};
+
+populate_request_params(OperationID, [FieldParams | T], Req0, ValidatorState, Model) ->
+ case populate_request_param(OperationID, FieldParams, Req0, ValidatorState) of
+ {ok, K, V, Req} ->
+ populate_request_params(OperationID, T, Req, ValidatorState, maps:put(K, V, Model));
+ Error ->
+ Error
+ end.
+
+populate_request_param(OperationID, Name, Req0, ValidatorState) ->
+ #{rules := Rules, source := Source} = request_param_info(OperationID, Name),
+ case get_value(Source, Name, Req0) of
+ {error, Reason, Req} ->
+ {error, Reason, Req};
+ {Value, Req} ->
+ case prepare_param(Rules, Name, Value, ValidatorState) of
+ {ok, Result} -> {ok, Name, Result, Req};
+ {error, Reason} ->
+ {error, Reason, Req}
+ end
+ end.
+
+-spec validate_response(
+ OperationID :: operation_id(),
+ Code :: 200..599,
+ Body :: jesse:json_term(),
+ ValidatorState :: jesse_state:state()
+) -> ok | no_return().
+{{#apiInfo}}{{#apis}}
+{{#operations}}{{#operation}}
+{{#responses}}
+validate_response('{{operationId}}', {{code}}, Body, ValidatorState) ->
+ validate_response_body('{{dataType}}', '{{baseType}}', Body, ValidatorState);
+{{/responses}}
+{{/operation}}{{/operations}}{{/apis}}{{/apiInfo}}
+
+validate_response(_OperationID, _Code, _Body, _ValidatorState) ->
+ ok.
+
+validate_response_body('list', ReturnBaseType, Body, ValidatorState) ->
+ [
+ validate(schema, ReturnBaseType, Item, ValidatorState)
+ || Item <- Body];
+
+validate_response_body(_, ReturnBaseType, Body, ValidatorState) ->
+ validate(schema, ReturnBaseType, Body, ValidatorState).
+
+%%%
+validate(Rule = required, Name, Value, _ValidatorState) ->
+ case Value of
+ undefined -> validation_error(Rule, Name);
+ _ -> ok
+ end;
+
+validate(not_required, _Name, _Value, _ValidatorState) ->
+ ok;
+
+validate(_, _Name, undefined, _ValidatorState) ->
+ ok;
+
+validate(Rule = {type, 'integer'}, Name, Value, _ValidatorState) ->
+ try
+ {ok, {{packageName}}_utils:to_int(Value)}
+ catch
+ error:badarg ->
+ validation_error(Rule, Name)
+ end;
+
+validate(Rule = {type, 'float'}, Name, Value, _ValidatorState) ->
+ try
+ {ok, {{packageName}}_utils:to_float(Value)}
+ catch
+ error:badarg ->
+ validation_error(Rule, Name)
+ end;
+
+validate(Rule = {type, 'binary'}, Name, Value, _ValidatorState) ->
+ case is_binary(Value) of
+ true -> ok;
+ false -> validation_error(Rule, Name)
+ end;
+
+validate(_Rule = {type, 'boolean'}, _Name, Value, _ValidatorState) when is_boolean(Value) ->
+ {ok, Value};
+
+validate(Rule = {type, 'boolean'}, Name, Value, _ValidatorState) ->
+ V = binary_to_lower(Value),
+ try
+ case binary_to_existing_atom(V, utf8) of
+ B when is_boolean(B) -> {ok, B};
+ _ -> validation_error(Rule, Name)
+ end
+ catch
+ error:badarg ->
+ validation_error(Rule, Name)
+ end;
+
+validate(Rule = {type, 'date'}, Name, Value, _ValidatorState) ->
+ case is_binary(Value) of
+ true -> ok;
+ false -> validation_error(Rule, Name)
+ end;
+
+validate(Rule = {type, 'datetime'}, Name, Value, _ValidatorState) ->
+ case is_binary(Value) of
+ true -> ok;
+ false -> validation_error(Rule, Name)
+ end;
+
+validate(Rule = {enum, Values}, Name, Value, _ValidatorState) ->
+ try
+ FormattedValue = erlang:binary_to_existing_atom(Value, utf8),
+ case lists:member(FormattedValue, Values) of
+ true -> {ok, FormattedValue};
+ false -> validation_error(Rule, Name)
+ end
+ catch
+ error:badarg ->
+ validation_error(Rule, Name)
+ end;
+
+validate(Rule = {max, Max}, Name, Value, _ValidatorState) ->
+ case Value =< Max of
+ true -> ok;
+ false -> validation_error(Rule, Name)
+ end;
+
+validate(Rule = {exclusive_max, ExclusiveMax}, Name, Value, _ValidatorState) ->
+ case Value > ExclusiveMax of
+ true -> ok;
+ false -> validation_error(Rule, Name)
+ end;
+
+validate(Rule = {min, Min}, Name, Value, _ValidatorState) ->
+ case Value >= Min of
+ true -> ok;
+ false -> validation_error(Rule, Name)
+ end;
+
+validate(Rule = {exclusive_min, ExclusiveMin}, Name, Value, _ValidatorState) ->
+ case Value =< ExclusiveMin of
+ true -> ok;
+ false -> validation_error(Rule, Name)
+ end;
+
+validate(Rule = {max_length, MaxLength}, Name, Value, _ValidatorState) ->
+ case size(Value) =< MaxLength of
+ true -> ok;
+ false -> validation_error(Rule, Name)
+ end;
+
+validate(Rule = {min_length, MinLength}, Name, Value, _ValidatorState) ->
+ case size(Value) >= MinLength of
+ true -> ok;
+ false -> validation_error(Rule, Name)
+ end;
+
+validate(Rule = {pattern, Pattern}, Name, Value, _ValidatorState) ->
+ {ok, MP} = re:compile(Pattern),
+ case re:run(Value, MP) of
+ {match, _} -> ok;
+ _ -> validation_error(Rule, Name)
+ end;
+
+validate(Rule = schema, Name, Value, ValidatorState) ->
+ Definition = list_to_binary("#/components/schemas/" ++ {{packageName}}_utils:to_list(Name)),
+ try
+ _ = validate_with_schema(Value, Definition, ValidatorState),
+ ok
+ catch
+ throw:[{schema_invalid, _, Error} | _] ->
+ Info = #{
+ type => schema_invalid,
+ error => Error
+ },
+ validation_error(Rule, Name, Info);
+ throw:[{data_invalid, Schema, Error, _, Path} | _] ->
+ Info = #{
+ type => data_invalid,
+ error => Error,
+ schema => Schema,
+ path => Path
+ },
+ validation_error(Rule, Name, Info)
+ end;
+
+validate(Rule, Name, _Value, _ValidatorState) ->
+ error_logger:info_msg("Can't validate ~p with ~p", [Name, Rule]),
+ error({unknown_validation_rule, Rule}).
+
+-spec validation_error(Rule :: any(), Name :: any()) -> no_return().
+
+validation_error(ViolatedRule, Name) ->
+ validation_error(ViolatedRule, Name, #{}).
+
+-spec validation_error(Rule :: any(), Name :: any(), Info :: #{}) -> no_return().
+
+validation_error(ViolatedRule, Name, Info) ->
+ throw({wrong_param, Name, ViolatedRule, Info}).
+
+-spec get_value(body | qs_val | header | binding, Name :: any(), Req0 :: cowboy_req:req()) ->
+ {Value :: any(), Req :: cowboy_req:req()} |
+ {error, Reason :: any(), Req :: cowboy_req:req()}.
+get_value(body, _Name, Req0) ->
+ {ok, Body, Req} = cowboy_req:read_body(Req0),
+ case prepare_body(Body) of
+ {error, Reason} ->
+ {error, Reason, Req};
+ Value ->
+ {Value, Req}
+ end;
+
+get_value(qs_val, Name, Req) ->
+ QS = cowboy_req:parse_qs(Req),
+ Value = {{packageName}}_utils:get_opt({{packageName}}_utils:to_qs(Name), QS),
+ {Value, Req};
+
+get_value(header, Name, Req) ->
+ Headers = cowboy_req:headers(Req),
+ Value = maps:get({{packageName}}_utils:to_header(Name), Headers, undefined),
+ {Value, Req};
+
+get_value(binding, Name, Req) ->
+ Value = cowboy_req:binding({{packageName}}_utils:to_binding(Name), Req),
+ {Value, Req}.
+
+prepare_body(Body) ->
+ case Body of
+ <<"">> -> <<"">>;
+ _ ->
+ try
+ jsx:decode(Body, [return_maps])
+ catch
+ error:_ ->
+ {error, {invalid_body, not_json, Body}}
+ end
+ end.
+
+validate_with_schema(Body, Definition, ValidatorState) ->
+ jesse_schema_validator:validate_with_state(
+ [{<<"$ref">>, Definition}],
+ Body,
+ ValidatorState
+ ).
+
+prepare_param(Rules, Name, Value, ValidatorState) ->
+ try
+ Result = lists:foldl(
+ fun(Rule, Acc) ->
+ case validate(Rule, Name, Acc, ValidatorState) of
+ ok -> Acc;
+ {ok, Prepared} -> Prepared
+ end
+ end,
+ Value,
+ Rules
+ ),
+ {ok, Result}
+ catch
+ throw:Reason ->
+ {error, Reason}
+ end.
+
+binary_to_lower(V) when is_binary(V) ->
+ list_to_binary(string:to_lower({{packageName}}_utils:to_list(V))).
diff --git a/modules/openapi-generator/src/main/resources/erlang-server-deprecated/app.src.mustache b/modules/openapi-generator/src/main/resources/erlang-server-deprecated/app.src.mustache
new file mode 100644
index 00000000000..a90c4e7cae7
--- /dev/null
+++ b/modules/openapi-generator/src/main/resources/erlang-server-deprecated/app.src.mustache
@@ -0,0 +1,19 @@
+{application, {{packageName}}, [
+ {description, {{#appDescription}}"{{.}}"{{/appDescription}}{{^appDescription}}"OpenAPI rest server library"{{/appDescription}}},
+ {vsn, "{{apiVersion}}"},
+ {registered, []},
+ {applications, [
+ kernel,
+ stdlib,
+ ssl,
+ inets,
+ jsx,
+ jesse,
+ cowboy
+ ]},
+ {env, [
+ ]},
+ {modules, []},
+ {licenses, [{{#licenseInfo}}"{{.}}"{{/licenseInfo}}]},
+ {links, [{{#infoUrl}}"{{.}}"{{/infoUrl}}]}
+]}.
diff --git a/modules/openapi-generator/src/main/resources/erlang-server-deprecated/auth.mustache b/modules/openapi-generator/src/main/resources/erlang-server-deprecated/auth.mustache
new file mode 100644
index 00000000000..3159e352a9c
--- /dev/null
+++ b/modules/openapi-generator/src/main/resources/erlang-server-deprecated/auth.mustache
@@ -0,0 +1,52 @@
+-module({{packageName}}_auth).
+
+-export([authorize_api_key/5]).
+
+-spec authorize_api_key(
+ LogicHandler :: atom(),
+ OperationID :: {{packageName}}_api:operation_id(),
+ From :: header | qs_val,
+ KeyParam :: iodata() | atom(),
+ Req ::cowboy_req:req()
+)-> {true, Context :: #{binary() => any()}, Req ::cowboy_req:req()} |
+ {false, AuthHeader :: binary(), Req ::cowboy_req:req()}.
+
+authorize_api_key(LogicHandler, OperationID, From, KeyParam, Req0) ->
+ {ApiKey, Req} = get_api_key(From, KeyParam, Req0),
+ case ApiKey of
+ undefined ->
+ AuthHeader = <<"">>,
+ {false, AuthHeader, Req};
+ _ ->
+ Result = {{packageName}}_logic_handler:authorize_api_key(
+ LogicHandler,
+ OperationID,
+ ApiKey
+ ),
+ case Result of
+ {{#authMethods}}
+ {{#isApiKey}}
+ {true, Context} ->
+ {true, Context, Req};
+ {{/isApiKey}}
+ {{/authMethods}}
+ false ->
+ AuthHeader = <<"">>,
+ {false, AuthHeader, Req}
+ end
+ end.
+
+get_api_key(header, KeyParam, Req) ->
+ Headers = cowboy_req:headers(Req),
+ {
+ maps:get(
+ {{packageName}}_utils:to_header(KeyParam),
+ Headers,
+ undefined
+ ),
+ Req
+ };
+
+get_api_key(qs_val, KeyParam, Req) ->
+ QS = cowboy_req:parse_qs(Req),
+ { {{packageName}}_utils:get_opt(KeyParam, QS), Req}.
diff --git a/modules/openapi-generator/src/main/resources/erlang-server-deprecated/default_logic_handler.mustache b/modules/openapi-generator/src/main/resources/erlang-server-deprecated/default_logic_handler.mustache
new file mode 100644
index 00000000000..1b39ed1d75a
--- /dev/null
+++ b/modules/openapi-generator/src/main/resources/erlang-server-deprecated/default_logic_handler.mustache
@@ -0,0 +1,32 @@
+-module({{packageName}}_default_logic_handler).
+
+-behaviour({{packageName}}_logic_handler).
+
+-export([handle_request/3]).
+{{#authMethods}}
+ {{#isApiKey}}
+-export([authorize_api_key/2]).
+ {{/isApiKey}}
+{{/authMethods}}
+
+{{#authMethods}}
+ {{#isApiKey}}
+-spec authorize_api_key(OperationID :: {{packageName}}_api:operation_id(), ApiKey :: binary()) -> {true, #{}}.
+
+authorize_api_key(_, _) -> {true, #{}}.
+ {{/isApiKey}}
+{{/authMethods}}
+
+-spec handle_request(
+ OperationID :: {{packageName}}_api:operation_id(),
+ Req :: cowboy_req:req(),
+ Context :: #{}
+) ->
+ {Status :: cowboy:http_status(), Headers :: cowboy:http_headers(), Body :: jsx:json_term()}.
+
+handle_request(OperationID, Req, Context) ->
+ error_logger:error_msg(
+ "Got not implemented request to process: ~p~n",
+ [{OperationID, Req, Context}]
+ ),
+ {501, #{}, #{}}.
diff --git a/modules/openapi-generator/src/main/resources/erlang-server-deprecated/handler.mustache b/modules/openapi-generator/src/main/resources/erlang-server-deprecated/handler.mustache
new file mode 100644
index 00000000000..70756b2549f
--- /dev/null
+++ b/modules/openapi-generator/src/main/resources/erlang-server-deprecated/handler.mustache
@@ -0,0 +1,252 @@
+%% basic handler
+-module({{classname}}).
+
+%% Cowboy REST callbacks
+-export([allowed_methods/2]).
+-export([init/2]).
+-export([allow_missing_post/2]).
+-export([content_types_accepted/2]).
+-export([content_types_provided/2]).
+-export([delete_resource/2]).
+-export([is_authorized/2]).
+-export([known_content_type/2]).
+-export([malformed_request/2]).
+-export([valid_content_headers/2]).
+-export([valid_entity_length/2]).
+
+%% Handlers
+-export([handle_request_json/2]).
+
+-record(state, {
+ operation_id :: {{packageName}}_api:operation_id(),
+ logic_handler :: atom(),
+ validator_state :: jesse_state:state(),
+ context=#{} :: #{}
+}).
+
+-type state() :: state().
+
+-spec init(Req :: cowboy_req:req(), Opts :: {{packageName}}_router:init_opts()) ->
+ {cowboy_rest, Req :: cowboy_req:req(), State :: state()}.
+
+init(Req, {Operations, LogicHandler, ValidatorMod}) ->
+ Method = cowboy_req:method(Req),
+ OperationID = maps:get(Method, Operations, undefined),
+
+ ValidatorState = ValidatorMod:get_validator_state(),
+
+ error_logger:info_msg("Attempt to process operation: ~p", [OperationID]),
+
+ State = #state{
+ operation_id = OperationID,
+ logic_handler = LogicHandler,
+ validator_state = ValidatorState
+ },
+ {cowboy_rest, Req, State}.
+
+-spec allowed_methods(Req :: cowboy_req:req(), State :: state()) ->
+ {Value :: [binary()], Req :: cowboy_req:req(), State :: state()}.
+
+{{#operations}}{{#operation}}
+allowed_methods(
+ Req,
+ State = #state{
+ operation_id = '{{operationId}}'
+ }
+) ->
+ {[<<"{{httpMethod}}">>], Req, State};
+{{/operation}}{{/operations}}
+allowed_methods(Req, State) ->
+ {[], Req, State}.
+
+-spec is_authorized(Req :: cowboy_req:req(), State :: state()) ->
+ {
+ Value :: true | {false, AuthHeader :: iodata()},
+ Req :: cowboy_req:req(),
+ State :: state()
+ }.
+{{#operations}}
+{{#operation}}
+{{#authMethods}}
+is_authorized(
+ Req0,
+ State = #state{
+ operation_id = '{{operationId}}' = OperationID,
+ logic_handler = LogicHandler
+ }
+) ->
+ {{#isApiKey}}
+ From = {{#isKeyInQuery}}qs_val{{/isKeyInQuery}}{{#isKeyInHeader}}header{{/isKeyInHeader}},
+ Result = {{packageName}}_auth:authorize_api_key(
+ LogicHandler,
+ OperationID,
+ From,
+ "{{keyParamName}}",
+ Req0
+ ),
+ case Result of
+ {true, Context, Req} -> {true, Req, State#state{context = Context}};
+ {false, AuthHeader, Req} -> {{false, AuthHeader}, Req, State}
+ end;
+ {{/isApiKey}}
+ {{#isOAuth}}
+ From = header,
+ Result = {{packageName}}_auth:authorize_api_key(
+ LogicHandler,
+ OperationID,
+ From,
+ "Authorization",
+ Req0
+ ),
+ case Result of
+ {true, Context, Req} -> {true, Req, State#state{context = Context}};
+ {false, AuthHeader, Req} -> {{false, AuthHeader}, Req, State}
+ end;
+ {{/isOAuth}}
+{{/authMethods}}
+{{/operation}}
+{{/operations}}
+{{^authMethods}}
+is_authorized(Req, State) ->
+ {true, Req, State}.
+{{/authMethods}}
+{{#authMethods}}
+is_authorized(Req, State) ->
+ {{false, <<"">>}, Req, State}.
+{{/authMethods}}
+
+-spec content_types_accepted(Req :: cowboy_req:req(), State :: state()) ->
+ {
+ Value :: [{binary(), AcceptResource :: atom()}],
+ Req :: cowboy_req:req(),
+ State :: state()
+ }.
+
+content_types_accepted(Req, State) ->
+ {[
+ {<<"application/json">>, handle_request_json}
+ ], Req, State}.
+
+-spec valid_content_headers(Req :: cowboy_req:req(), State :: state()) ->
+ {Value :: boolean(), Req :: cowboy_req:req(), State :: state()}.
+{{#operations}}{{#operation}}
+valid_content_headers(
+ Req0,
+ State = #state{
+ operation_id = '{{operationId}}'
+ }
+) ->
+ Headers = [{{#headerParams}}"{{baseName}}"{{^-last}},{{/-last}}{{/headerParams}}],
+ {Result, Req} = validate_headers(Headers, Req0),
+ {Result, Req, State};
+{{/operation}}{{/operations}}
+valid_content_headers(Req, State) ->
+ {false, Req, State}.
+
+-spec content_types_provided(Req :: cowboy_req:req(), State :: state()) ->
+ {
+ Value :: [{binary(), ProvideResource :: atom()}],
+ Req :: cowboy_req:req(),
+ State :: state()
+ }.
+
+content_types_provided(Req, State) ->
+ {[
+ {<<"application/json">>, handle_request_json}
+ ], Req, State}.
+
+-spec malformed_request(Req :: cowboy_req:req(), State :: state()) ->
+ {Value :: false, Req :: cowboy_req:req(), State :: state()}.
+
+malformed_request(Req, State) ->
+ {false, Req, State}.
+
+-spec allow_missing_post(Req :: cowboy_req:req(), State :: state()) ->
+ {Value :: false, Req :: cowboy_req:req(), State :: state()}.
+
+allow_missing_post(Req, State) ->
+ {false, Req, State}.
+
+-spec delete_resource(Req :: cowboy_req:req(), State :: state()) ->
+ processed_response().
+
+delete_resource(Req, State) ->
+ handle_request_json(Req, State).
+
+-spec known_content_type(Req :: cowboy_req:req(), State :: state()) ->
+ {Value :: true, Req :: cowboy_req:req(), State :: state()}.
+
+known_content_type(Req, State) ->
+ {true, Req, State}.
+
+-spec valid_entity_length(Req :: cowboy_req:req(), State :: state()) ->
+ {Value :: true, Req :: cowboy_req:req(), State :: state()}.
+
+valid_entity_length(Req, State) ->
+ %% @TODO check the length
+ {true, Req, State}.
+
+%%%%
+-type result_ok() :: {
+ ok,
+ {Status :: cowboy:http_status(), Headers :: cowboy:http_headers(), Body :: iodata()}
+}.
+
+-type result_error() :: {error, Reason :: any()}.
+
+-type processed_response() :: {stop, cowboy_req:req(), state()}.
+
+-spec process_response(result_ok() | result_error(), cowboy_req:req(), state()) ->
+ processed_response().
+
+process_response(Response, Req0, State = #state{operation_id = OperationID}) ->
+ case Response of
+ {ok, {Code, Headers, Body}} ->
+ Req = cowboy_req:reply(Code, Headers, Body, Req0),
+ {stop, Req, State};
+ {error, Message} ->
+ error_logger:error_msg("Unable to process request for ~p: ~p", [OperationID, Message]),
+
+ Req = cowboy_req:reply(400, Req0),
+ {stop, Req, State}
+ end.
+
+-spec handle_request_json(cowboy_req:req(), state()) -> processed_response().
+
+handle_request_json(
+ Req0,
+ State = #state{
+ operation_id = OperationID,
+ logic_handler = LogicHandler,
+ validator_state = ValidatorState
+ }
+) ->
+ case {{packageName}}_api:populate_request(OperationID, Req0, ValidatorState) of
+ {ok, Populated, Req1} ->
+ {Code, Headers, Body} = {{packageName}}_logic_handler:handle_request(
+ LogicHandler,
+ OperationID,
+ Req1,
+ maps:merge(State#state.context, Populated)
+ ),
+ _ = {{packageName}}_api:validate_response(
+ OperationID,
+ Code,
+ Body,
+ ValidatorState
+ ),
+ PreparedBody = prepare_body(Code, Body),
+ Response = {ok, {Code, Headers, PreparedBody}},
+ process_response(Response, Req1, State);
+ {error, Reason, Req1} ->
+ process_response({error, Reason}, Req1, State)
+ end.
+
+validate_headers(_, Req) -> {true, Req}.
+
+prepare_body(204, Body) when map_size(Body) == 0; length(Body) == 0 ->
+ <<>>;
+prepare_body(304, Body) when map_size(Body) == 0; length(Body) == 0 ->
+ <<>>;
+prepare_body(_Code, Body) ->
+ jsx:encode(Body).
diff --git a/modules/openapi-generator/src/main/resources/erlang-server-deprecated/logic_handler.mustache b/modules/openapi-generator/src/main/resources/erlang-server-deprecated/logic_handler.mustache
new file mode 100644
index 00000000000..eb0688e682c
--- /dev/null
+++ b/modules/openapi-generator/src/main/resources/erlang-server-deprecated/logic_handler.mustache
@@ -0,0 +1,60 @@
+-module({{packageName}}_logic_handler).
+
+-export([handle_request/4]).
+{{#authMethods}}
+{{#isApiKey}}
+{{#-first}}
+-export([authorize_api_key/3]).
+{{/-first}}
+{{/isApiKey}}
+{{/authMethods}}
+{{^authMethods}}
+-export([authorize_api_key/3]).
+{{/authMethods}}
+-type context() :: #{binary() => any()}.
+-type handler_response() ::{
+ Status :: cowboy:http_status(),
+ Headers :: cowboy:http_headers(),
+ Body :: jsx:json_term()}.
+
+-export_type([handler_response/0]).
+
+{{#authMethods}}
+ {{#isApiKey}}
+-callback authorize_api_key(
+ OperationID :: {{packageName}}_api:operation_id(),
+ ApiKey :: binary()
+) ->
+ Result :: boolean() | {boolean(), context()}.
+ {{/isApiKey}}
+{{/authMethods}}
+
+
+-callback handle_request(OperationID :: {{packageName}}_api:operation_id(), cowboy_req:req(), Context :: context()) ->
+ handler_response().
+
+-spec handle_request(
+ Handler :: atom(),
+ OperationID :: {{packageName}}_api:operation_id(),
+ Request :: cowboy_req:req(),
+ Context :: context()
+) ->
+ handler_response().
+
+handle_request(Handler, OperationID, Req, Context) ->
+ Handler:handle_request(OperationID, Req, Context).
+
+{{#authMethods}}
+ {{#isApiKey}}
+-spec authorize_api_key(Handler :: atom(), OperationID :: {{packageName}}_api:operation_id(), ApiKey :: binary()) ->
+ Result :: false | {true, context()}.
+authorize_api_key(Handler, OperationID, ApiKey) ->
+ Handler:authorize_api_key(OperationID, ApiKey).
+ {{/isApiKey}}
+{{/authMethods}}
+{{^authMethods}}
+-spec authorize_api_key(Handler :: atom(), OperationID :: {{packageName}}_api:operation_id(), ApiKey :: binary()) ->
+ Result :: false.
+authorize_api_key(_Handler, _OperationID, _ApiKey) ->
+ false.
+{{/authMethods}}
diff --git a/modules/openapi-generator/src/main/resources/erlang-server-deprecated/openapi.mustache b/modules/openapi-generator/src/main/resources/erlang-server-deprecated/openapi.mustache
new file mode 100644
index 00000000000..2c1b461cf00
--- /dev/null
+++ b/modules/openapi-generator/src/main/resources/erlang-server-deprecated/openapi.mustache
@@ -0,0 +1 @@
+{{{openapi-json}}}
diff --git a/modules/openapi-generator/src/main/resources/erlang-server-deprecated/rebar.config.mustache b/modules/openapi-generator/src/main/resources/erlang-server-deprecated/rebar.config.mustache
new file mode 100644
index 00000000000..743b108f384
--- /dev/null
+++ b/modules/openapi-generator/src/main/resources/erlang-server-deprecated/rebar.config.mustache
@@ -0,0 +1,6 @@
+{deps, [
+ {cowboy, {git, "https://github.com/ninenines/cowboy.git", {tag, "2.8.0"}}},
+ {rfc3339, {git, "https://github.com/talentdeficit/rfc3339.git", {tag, "master"}}},
+ {jsx, {git, "https://github.com/talentdeficit/jsx.git", {tag, "v3.1.0"}}},
+ {jesse, {git, "https://github.com/for-GET/jesse.git", {tag, "1.5.6"}}}
+]}.
diff --git a/modules/openapi-generator/src/main/resources/erlang-server-deprecated/router.mustache b/modules/openapi-generator/src/main/resources/erlang-server-deprecated/router.mustache
new file mode 100644
index 00000000000..e2efc2206bc
--- /dev/null
+++ b/modules/openapi-generator/src/main/resources/erlang-server-deprecated/router.mustache
@@ -0,0 +1,78 @@
+-module({{packageName}}_router).
+
+-export([get_paths/1, get_validator_state/0]).
+
+-type operations() :: #{
+ Method :: binary() => {{packageName}}_api:operation_id()
+}.
+
+-type init_opts() :: {
+ Operations :: operations(),
+ LogicHandler :: atom(),
+ ValidatorMod :: module()
+}.
+
+-export_type([init_opts/0]).
+
+-spec get_paths(LogicHandler :: atom()) -> [{'_',[{
+ Path :: string(),
+ Handler :: atom(),
+ InitOpts :: init_opts()
+}]}].
+
+get_paths(LogicHandler) ->
+ ValidatorState = prepare_validator(),
+ PreparedPaths = maps:fold(
+ fun(Path, #{operations := Operations, handler := Handler}, Acc) ->
+ [{Path, Handler, Operations} | Acc]
+ end,
+ [],
+ group_paths()
+ ),
+ [
+ {'_',
+ [{P, H, {O, LogicHandler, ValidatorState}} || {P, H, O} <- PreparedPaths]
+ }
+ ].
+
+group_paths() ->
+ maps:fold(
+ fun(OperationID, #{path := Path, method := Method, handler := Handler}, Acc) ->
+ case maps:find(Path, Acc) of
+ {ok, PathInfo0 = #{operations := Operations0}} ->
+ Operations = Operations0#{Method => OperationID},
+ PathInfo = PathInfo0#{operations => Operations},
+ Acc#{Path => PathInfo};
+ error ->
+ Operations = #{Method => OperationID},
+ PathInfo = #{handler => Handler, operations => Operations},
+ Acc#{Path => PathInfo}
+ end
+ end,
+ #{},
+ get_operations()
+ ).
+
+get_operations() ->
+ #{ {{#apiInfo}}{{#apis}}{{#operations}}{{#operation}}
+ '{{operationId}}' => #{
+ path => "{{{basePathWithoutHost}}}{{{path}}}",
+ method => <<"{{httpMethod}}">>,
+ handler => '{{classname}}'
+ }{{^-last}},{{/-last}}{{/operation}}{{^-last}},{{/-last}}{{/operations}}{{/apis}}{{/apiInfo}}
+ }.
+
+get_validator_state() ->
+ persistent_term:get({?MODULE, validator_state}).
+
+
+prepare_validator() ->
+ R = jsx:decode(element(2, file:read_file(get_openapi_path()))),
+ JesseState = jesse_state:new(R, [{default_schema_ver, <<"http://json-schema.org/draft-04/schema#">>}]),
+ persistent_term:put({?MODULE, validator_state}, JesseState),
+ ?MODULE.
+
+
+get_openapi_path() ->
+ {ok, AppName} = application:get_application(?MODULE),
+ filename:join({{packageName}}_utils:priv_dir(AppName), "{{{openAPISpecName}}}.json").
diff --git a/modules/openapi-generator/src/main/resources/erlang-server-deprecated/server.mustache b/modules/openapi-generator/src/main/resources/erlang-server-deprecated/server.mustache
new file mode 100644
index 00000000000..cca0af57a84
--- /dev/null
+++ b/modules/openapi-generator/src/main/resources/erlang-server-deprecated/server.mustache
@@ -0,0 +1,67 @@
+-module({{packageName}}_server).
+
+
+-define(DEFAULT_LOGIC_HANDLER, {{packageName}}_default_logic_handler).
+
+-export([start/2]).
+
+-spec start( ID :: any(), #{
+ ip => inet:ip_address(),
+ port => inet:port_number(),
+ logic_handler => module(),
+ net_opts => []
+}) -> {ok, pid()} | {error, any()}.
+
+start(ID, #{
+ ip := IP ,
+ port := Port,
+ net_opts := NetOpts
+} = Params) ->
+ {Transport, TransportOpts} = get_socket_transport(IP, Port, NetOpts),
+ LogicHandler = maps:get(logic_handler, Params, ?DEFAULT_LOGIC_HANDLER),
+ ExtraOpts = maps:get(cowboy_extra_opts, Params, []),
+ CowboyOpts = get_cowboy_config(LogicHandler, ExtraOpts),
+ case Transport of
+ ssl ->
+ cowboy:start_tls(ID, TransportOpts, CowboyOpts);
+ tcp ->
+ cowboy:start_clear(ID, TransportOpts, CowboyOpts)
+ end.
+
+get_socket_transport(IP, Port, Options) ->
+ Opts = [
+ {ip, IP},
+ {port, Port}
+ ],
+ case {{packageName}}_utils:get_opt(ssl, Options) of
+ SslOpts = [_|_] ->
+ {ssl, Opts ++ SslOpts};
+ undefined ->
+ {tcp, Opts}
+ end.
+
+get_cowboy_config(LogicHandler, ExtraOpts) ->
+ get_cowboy_config(LogicHandler, ExtraOpts, get_default_opts(LogicHandler)).
+
+get_cowboy_config(_LogicHandler, [], Opts) ->
+ Opts;
+
+get_cowboy_config(LogicHandler, [{env, Env} | Rest], Opts) ->
+ NewEnv = case proplists:get_value(dispatch, Env) of
+ undefined -> [get_default_dispatch(LogicHandler) | Env];
+ _ -> Env
+ end,
+ get_cowboy_config(LogicHandler, Rest, store_key(env, NewEnv, Opts));
+
+get_cowboy_config(LogicHandler, [{Key, Value}| Rest], Opts) ->
+ get_cowboy_config(LogicHandler, Rest, store_key(Key, Value, Opts)).
+
+get_default_dispatch(LogicHandler) ->
+ Paths = {{packageName}}_router:get_paths(LogicHandler),
+ #{dispatch => cowboy_router:compile(Paths)}.
+
+get_default_opts(LogicHandler) ->
+ #{env => get_default_dispatch(LogicHandler)}.
+
+store_key(Key, Value, Opts) ->
+ maps:put(Key, Value, Opts).
diff --git a/modules/openapi-generator/src/main/resources/erlang-server-deprecated/utils.mustache b/modules/openapi-generator/src/main/resources/erlang-server-deprecated/utils.mustache
new file mode 100644
index 00000000000..b6701add7fc
--- /dev/null
+++ b/modules/openapi-generator/src/main/resources/erlang-server-deprecated/utils.mustache
@@ -0,0 +1,173 @@
+-module({{packageName}}_utils).
+
+-export([to_binary/1]).
+-export([to_list/1]).
+-export([to_float/1]).
+-export([to_int/1]).
+-export([to_lower/1]).
+-export([to_upper/1]).
+-export([set_resp_headers/2]).
+-export([to_header/1]).
+-export([to_qs/1]).
+-export([to_binding/1]).
+-export([get_opt/2]).
+-export([get_opt/3]).
+-export([priv_dir/0]).
+-export([priv_dir/1]).
+-export([priv_path/1]).
+
+
+-spec to_binary(iodata() | atom() | number()) -> binary().
+
+to_binary(V) when is_binary(V) -> V;
+to_binary(V) when is_list(V) -> iolist_to_binary(V);
+to_binary(V) when is_atom(V) -> atom_to_binary(V, utf8);
+to_binary(V) when is_integer(V) -> integer_to_binary(V);
+to_binary(V) when is_float(V) -> float_to_binary(V).
+
+-spec to_list(iodata() | atom() | number()) -> string().
+
+to_list(V) when is_list(V) -> V;
+to_list(V) -> binary_to_list(to_binary(V)).
+
+-spec to_float(iodata()) -> number().
+
+to_float(V) ->
+ Data = iolist_to_binary([V]),
+ case binary:split(Data, <<$.>>) of
+ [Data] ->
+ binary_to_integer(Data);
+ [<<>>, _] ->
+ binary_to_float(<<$0, Data/binary>>);
+ _ ->
+ binary_to_float(Data)
+ end.
+
+%%
+
+-spec to_int(integer() | binary() | list()) -> integer().
+
+to_int(Data) when is_integer(Data) ->
+ Data;
+to_int(Data) when is_binary(Data) ->
+ binary_to_integer(Data);
+to_int(Data) when is_list(Data) ->
+ list_to_integer(Data).
+
+-spec set_resp_headers([{binary(), iodata()}], cowboy_req:req()) -> cowboy_req:req().
+
+set_resp_headers([], Req) ->
+ Req;
+set_resp_headers([{K, V} | T], Req0) ->
+ Req = cowboy_req:set_resp_header(K, V, Req0),
+ set_resp_headers(T, Req).
+
+-spec to_header(iodata() | atom() | number()) -> binary().
+
+to_header(Name) ->
+ Prepared = to_binary(Name),
+ to_lower(Prepared).
+
+-spec to_qs(iodata() | atom() | number()) -> binary().
+
+to_qs(Name) ->
+ to_binary(Name).
+
+-spec to_binding(iodata() | atom() | number()) -> atom().
+
+to_binding(Name) ->
+ Prepared = to_binary(Name),
+ binary_to_atom(Prepared, utf8).
+
+-spec get_opt(any(), []) -> any().
+
+get_opt(Key, Opts) ->
+ get_opt(Key, Opts, undefined).
+
+-spec get_opt(any(), [], any()) -> any().
+
+get_opt(Key, Opts, Default) ->
+ case lists:keyfind(Key, 1, Opts) of
+ {_, Value} -> Value;
+ false -> Default
+ end.
+
+-spec priv_dir() -> file:filename().
+
+priv_dir() ->
+ {ok, AppName} = application:get_application(),
+ priv_dir(AppName).
+
+-spec priv_dir(Application :: atom()) -> file:filename().
+
+priv_dir(AppName) ->
+ case code:priv_dir(AppName) of
+ Value when is_list(Value) ->
+ Value ++ "/";
+ _Error ->
+ select_priv_dir([filename:join(["apps", atom_to_list(AppName), "priv"]), "priv"])
+ end.
+
+-spec priv_path(Relative :: file:filename()) -> file:filename().
+
+priv_path(Relative) ->
+ filename:join(priv_dir(), Relative).
+
+-include_lib("kernel/include/file.hrl").
+
+select_priv_dir(Paths) ->
+ case lists:dropwhile(fun test_priv_dir/1, Paths) of
+ [Path | _] -> Path;
+ _ -> exit(no_priv_dir)
+ end.
+
+test_priv_dir(Path) ->
+ case file:read_file_info(Path) of
+ {ok, #file_info{type = directory}} ->
+ false;
+ _ ->
+ true
+ end.
+
+
+%%
+
+-spec to_lower(binary()) -> binary().
+
+to_lower(S) ->
+ to_case(lower, S, <<>>).
+
+-spec to_upper(binary()) -> binary().
+
+to_upper(S) ->
+ to_case(upper, S, <<>>).
+
+to_case(_Case, <<>>, Acc) ->
+ Acc;
+
+to_case(_Case, <>, _Acc) when C > 127 ->
+ error(badarg);
+
+to_case(Case = lower, <>, Acc) ->
+ to_case(Case, Rest, <>);
+
+to_case(Case = upper, <>, Acc) ->
+ to_case(Case, Rest, <>).
+
+to_lower_char(C) when is_integer(C), $A =< C, C =< $Z ->
+ C + 32;
+to_lower_char(C) when is_integer(C), 16#C0 =< C, C =< 16#D6 ->
+ C + 32;
+to_lower_char(C) when is_integer(C), 16#D8 =< C, C =< 16#DE ->
+ C + 32;
+to_lower_char(C) ->
+ C.
+
+to_upper_char(C) when is_integer(C), $a =< C, C =< $z ->
+ C - 32;
+to_upper_char(C) when is_integer(C), 16#E0 =< C, C =< 16#F6 ->
+ C - 32;
+to_upper_char(C) when is_integer(C), 16#F8 =< C, C =< 16#FE ->
+ C - 32;
+to_upper_char(C) ->
+ C.