diff --git a/bin/openapi3/scala-sttp-petstore.sh b/bin/openapi3/scala-sttp-petstore.sh
new file mode 100644
index 00000000000..2a9753df295
--- /dev/null
+++ b/bin/openapi3/scala-sttp-petstore.sh
@@ -0,0 +1,32 @@
+#!/bin/sh
+
+SCRIPT="$0"
+echo "# START SCRIPT: $SCRIPT"
+
+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/openapi-generator-cli/target/openapi-generator-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} -Xmx1024M -DloggerPath=conf/log4j.properties"
+ags="generate --artifact-id "scala-sttp-petstore-client" -t modules/openapi-generator/src/main/resources/scala-sttp-client -i modules/openapi-generator/src/test/resources/3_0/petstore.yaml -g scala-sttp -o samples/client/petstore/scala-sttp $@"
+
+java $JAVA_OPTS -jar $executable $ags
diff --git a/docs/generators.md b/docs/generators.md
index c8dd81b0cc7..ab157a3e460 100644
--- a/docs/generators.md
+++ b/docs/generators.md
@@ -54,6 +54,7 @@ The following generators are available:
* [scala-akka](generators/scala-akka.md)
* [scala-gatling](generators/scala-gatling.md)
* [scala-httpclient-deprecated (deprecated)](generators/scala-httpclient-deprecated.md)
+* [scala-sttp](generators/scala-sttp.md)
* [scalaz](generators/scalaz.md)
* [swift2-deprecated (deprecated)](generators/swift2-deprecated.md)
* [swift3-deprecated (deprecated)](generators/swift3-deprecated.md)
diff --git a/docs/generators/scala-sttp.md b/docs/generators/scala-sttp.md
new file mode 100644
index 00000000000..bcf665f875b
--- /dev/null
+++ b/docs/generators/scala-sttp.md
@@ -0,0 +1,216 @@
+---
+title: Config Options for scala-sttp
+sidebar_label: scala-sttp
+---
+
+| Option | Description | Values | Default |
+| ------ | ----------- | ------ | ------- |
+|allowUnicodeIdentifiers|boolean, toggles whether unicode identifiers are allowed in names or not, default is false| |false|
+|apiPackage|package for generated api classes| |null|
+|ensureUniqueParams|Whether to ensure parameter names are unique in an operation (rename parameters that are not).| |true|
+|mainPackage|Top-level package name, which defines 'apiPackage', 'modelPackage', 'invokerPackage'| |org.openapitools.client|
+|modelPackage|package for generated models| |null|
+|prependFormOrBodyParameters|Add form or body parameters to the beginning of the parameter list.| |false|
+|sortModelPropertiesByRequiredFlag|Sort model properties to place required parameters before optional parameters.| |true|
+|sortParamsByRequiredFlag|Sort method arguments to place required parameters before optional parameters.| |true|
+|sourceFolder|source folder for generated code| |null|
+
+## IMPORT MAPPING
+
+| Type/Alias | Imports |
+| ---------- | ------- |
+|Array|java.util.List|
+|ArrayList|java.util.ArrayList|
+|BigDecimal|java.math.BigDecimal|
+|Date|java.util.Date|
+|DateTime|org.joda.time.DateTime|
+|File|java.io.File|
+|HashMap|java.util.HashMap|
+|ListBuffer|scala.collection.mutable.ListBuffer|
+|ListSet|scala.collection.immutable.ListSet|
+|LocalDate|org.joda.time.*|
+|LocalDateTime|org.joda.time.*|
+|LocalTime|org.joda.time.*|
+|Timestamp|java.sql.Timestamp|
+|URI|java.net.URI|
+|UUID|java.util.UUID|
+
+
+## INSTANTIATION TYPES
+
+| Type/Alias | Instantiated By |
+| ---------- | --------------- |
+|array|ListBuffer|
+|map|Map|
+|set|Set|
+
+
+## LANGUAGE PRIMITIVES
+
+
+- Any
+- Array
+- Boolean
+- Double
+- Float
+- Int
+- List
+- Long
+- Map
+- Object
+- Seq
+- String
+- boolean
+
+
+## RESERVED WORDS
+
+
+- abstract
+- case
+- catch
+- class
+- def
+- do
+- else
+- extends
+- false
+- final
+- finally
+- for
+- forsome
+- if
+- implicit
+- import
+- lazy
+- match
+- new
+- null
+- object
+- override
+- package
+- private
+- protected
+- return
+- sealed
+- super
+- this
+- throw
+- trait
+- true
+- try
+- type
+- val
+- var
+- while
+- with
+- yield
+
+
+## FEATURE SET
+
+
+### Client Modification Feature
+| Name | Supported | Defined By |
+| ---- | --------- | ---------- |
+|BasePath|✓|ToolingExtension
+|Authorizations|✗|ToolingExtension
+|UserAgent|✓|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
+|Array|✓|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
+
+### 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
+
+### 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/ScalaSttpClientCodegen.java b/modules/openapi-generator/src/main/java/org/openapitools/codegen/languages/ScalaSttpClientCodegen.java
new file mode 100644
index 00000000000..a00f57263a3
--- /dev/null
+++ b/modules/openapi-generator/src/main/java/org/openapitools/codegen/languages/ScalaSttpClientCodegen.java
@@ -0,0 +1,73 @@
+package org.openapitools.codegen.languages;
+
+import io.swagger.v3.oas.models.Operation;
+import io.swagger.v3.oas.models.servers.Server;
+import org.openapitools.codegen.CodegenConfig;
+import org.openapitools.codegen.CodegenOperation;
+import org.openapitools.codegen.SupportingFile;
+
+import java.io.File;
+import java.util.List;
+
+public class ScalaSttpClientCodegen extends ScalaAkkaClientCodegen implements CodegenConfig {
+ protected String mainPackage = "org.openapitools.client";
+
+ public ScalaSttpClientCodegen() {
+ super();
+ }
+
+
+ @Override
+ public void processOpts() {
+ super.processOpts();
+ if (additionalProperties.containsKey("mainPackage")) {
+ setMainPackage((String) additionalProperties.get("mainPackage"));
+ additionalProperties.replace("configKeyPath", this.configKeyPath);
+ apiPackage = mainPackage + ".api";
+ modelPackage = mainPackage + ".model";
+ invokerPackage = mainPackage + ".core";
+ additionalProperties.put("apiPackage", apiPackage);
+ additionalProperties.put("modelPackage", modelPackage);
+ }
+
+ if (!additionalProperties.containsKey("java8")) {
+ additionalProperties.put("joda", "true");
+ }
+
+ supportingFiles.clear();
+ supportingFiles.add(new SupportingFile("README.mustache", "", "README.md"));
+ supportingFiles.add(new SupportingFile("build.sbt.mustache", "", "build.sbt"));
+ final String invokerFolder = (sourceFolder + File.separator + invokerPackage).replace(".", File.separator);
+ supportingFiles.add(new SupportingFile("requests.mustache", invokerFolder, "requests.scala"));
+ supportingFiles.add(new SupportingFile("apiInvoker.mustache", invokerFolder, "ApiInvoker.scala"));
+ final String apiFolder = (sourceFolder + File.separator + apiPackage).replace(".", File.separator);
+ supportingFiles.add(new SupportingFile("enumsSerializers.mustache", apiFolder, "EnumsSerializers.scala"));
+ supportingFiles.add(new SupportingFile("serializers.mustache", invokerFolder, "Serializers.scala"));
+ }
+
+ @Override
+ public String getName() {
+ return "scala-sttp";
+ }
+
+ @Override
+ public String getHelp() {
+ return "Generates a Scala client library base on Sttp.";
+ }
+
+ @Override
+ public String encodePath(String input) {
+ String result = super.encodePath(input);
+ return result.replace("{","${");
+ }
+
+ @Override
+ public CodegenOperation fromOperation(String path,
+ String httpMethod,
+ Operation operation,
+ List servers) {
+ CodegenOperation op = super.fromOperation(path, httpMethod, operation, servers);
+ op.path = encodePath(path);
+ return op;
+ }
+}
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 c48f628a3aa..89cbc16b896 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
@@ -126,3 +126,4 @@ org.openapitools.codegen.languages.AsciidocDocumentationCodegen
org.openapitools.codegen.languages.FsharpFunctionsServerCodegen
org.openapitools.codegen.languages.MarkdownDocumentationCodegen
+org.openapitools.codegen.languages.ScalaSttpClientCodegen
diff --git a/modules/openapi-generator/src/main/resources/scala-sttp-client/README.mustache b/modules/openapi-generator/src/main/resources/scala-sttp-client/README.mustache
new file mode 100644
index 00000000000..0a61209568d
--- /dev/null
+++ b/modules/openapi-generator/src/main/resources/scala-sttp-client/README.mustache
@@ -0,0 +1,107 @@
+# {{artifactId}}
+
+{{appName}}
+- API version: {{appVersion}}
+{{^hideGenerationTimestamp}}
+ - Build date: {{generatedDate}}
+{{/hideGenerationTimestamp}}
+
+{{#appDescriptionWithNewLines}}{{{appDescriptionWithNewLines}}}{{/appDescriptionWithNewLines}}
+
+{{#infoUrl}}
+ For more information, please visit [{{{infoUrl}}}]({{{infoUrl}}})
+{{/infoUrl}}
+
+*Automatically generated by the [OpenAPI Generator](https://openapi-generator.tech)*
+
+## Requirements
+
+Building the API client library requires:
+1. Java 1.7+
+2. Maven/Gradle/SBT
+
+## Installation
+
+To install the API client library to your local Maven repository, simply execute:
+
+```shell
+mvn clean install
+```
+
+To deploy it to a remote Maven repository instead, configure the settings of the repository and execute:
+
+```shell
+mvn clean deploy
+```
+
+Refer to the [OSSRH Guide](http://central.sonatype.org/pages/ossrh-guide.html) for more information.
+
+### Maven users
+
+Add this dependency to your project's POM:
+
+```xml
+
+ {{{groupId}}}
+ {{{artifactId}}}
+ {{{artifactVersion}}}
+ compile
+
+```
+
+### Gradle users
+
+Add this dependency to your project's build file:
+
+```groovy
+compile "{{{groupId}}}:{{{artifactId}}}:{{{artifactVersion}}}"
+```
+
+### SBT users
+
+```scala
+libraryDependencies += "{{{groupId}}}" % "{{{artifactId}}}" % "{{{artifactVersion}}}"
+```
+
+## Getting Started
+
+## Documentation for API Endpoints
+
+All URIs are relative to *{{basePath}}*
+
+Class | Method | HTTP request | Description
+------------ | ------------- | ------------- | -------------
+{{#apiInfo}}{{#apis}}{{#operations}}{{#operation}}*{{classname}}* | **{{operationId}}** | **{{httpMethod}}** {{path}} | {{#summary}}{{summary}}{{/summary}}
+{{/operation}}{{/operations}}{{/apis}}{{/apiInfo}}
+
+## Documentation for Models
+
+{{#models}}{{#model}} - [{{classname}}]({{modelDocPath}}{{classname}}.md)
+{{/model}}{{/models}}
+
+## Documentation for Authorization
+
+{{^authMethods}}All endpoints do not require authorization.
+{{/authMethods}}Authentication schemes defined for the API:
+{{#authMethods}}### {{name}}
+
+{{#isApiKey}}- **Type**: API key
+- **API key parameter name**: {{keyParamName}}
+- **Location**: {{#isKeyInQuery}}URL query string{{/isKeyInQuery}}{{#isKeyInHeader}}HTTP header{{/isKeyInHeader}}
+{{/isApiKey}}
+{{#isBasic}}- **Type**: HTTP basic authentication
+{{/isBasic}}
+{{#isOAuth}}- **Type**: OAuth
+- **Flow**: {{flow}}
+- **Authorization URL**: {{authorizationUrl}}
+- **Scopes**: {{^scopes}}N/A{{/scopes}}
+{{#scopes}} - {{scope}}: {{description}}
+{{/scopes}}
+{{/isOAuth}}
+
+{{/authMethods}}
+
+## Author
+
+{{#apiInfo}}{{#apis}}{{^hasMore}}{{infoEmail}}
+{{/hasMore}}{{/apis}}{{/apiInfo}}
diff --git a/modules/openapi-generator/src/main/resources/scala-sttp-client/api.mustache b/modules/openapi-generator/src/main/resources/scala-sttp-client/api.mustache
new file mode 100644
index 00000000000..412bfca507d
--- /dev/null
+++ b/modules/openapi-generator/src/main/resources/scala-sttp-client/api.mustache
@@ -0,0 +1,45 @@
+{{>licenseInfo}}
+package {{package}}
+
+{{#imports}}
+import {{import}}
+{{/imports}}
+import {{mainPackage}}.core._
+import alias._
+import sttp.client._
+import sttp.model.Method
+
+{{#operations}}
+object {{classname}} {
+
+ def apply(baseUrl: String = "{{{basePath}}}")(implicit serializer: SttpSerializer) = new {{classname}}(baseUrl)
+}
+
+class {{classname}}(baseUrl: String)(implicit serializer: SttpSerializer) {
+
+ import Helpers._
+ import serializer._
+
+{{#operation}}
+{{#javadocRenderer}}
+{{>javadoc}}
+{{/javadocRenderer}}
+ def {{operationId}}({{>methodParameters}}): ApiRequestT[{{>operationReturnType}}] =
+ basicRequest
+ .method(Method.{{httpMethod.toUpperCase}}, uri"$baseUrl{{{path}}}{{#queryParams.0}}?{{#queryParams}}{{baseName}}=${{{paramName}}}{{^-last}}&{{/-last}}{{/queryParams}}{{/queryParams.0}}{{#isApiKey}}{{#isKeyInQuery}}{{^queryParams.0}}?{{/queryParams.0}}{{#queryParams.0}}&{{/queryParams.0}}{{keyParamName}}=${apiKey.value}&{{/isKeyInQuery}}{{/isApiKey}}")
+ .contentType({{#consumes.0}}"{{{mediaType}}}"{{/consumes.0}}{{^consumes}}"application/json"{{/consumes}}){{#headerParams}}
+ .header({{>paramCreation}}){{/headerParams}}{{#authMethods}}{{#isBasic}}{{#isBasicBasic}}
+ .auth.withCredentials(basicAuth.user, basicAuth.password){{/isBasicBasic}}{{#isBasicBearer}}
+ .auth.bearer(bearerToken.token){{/isBasicBearer}}{{/isBasic}}{{#isApiKey}}{{#isKeyInHeader}}
+ .header("{{keyParamName}}", apiKey.value){{/isKeyInHeader}}{{#isKeyInCookie}}
+ .cookie("{{keyParamName}}", apiKey.value){{/isKeyInCookie}}{{/isApiKey}}{{/authMethods}}{{#formParams.0}}
+ .body(Map({{#formParams}}
+ {{>paramFormCreation}},{{/formParams}}
+ )){{/formParams.0}}{{#bodyParam}}
+ .body({{paramName}}){{/bodyParam}}
+ .response(asJson[{{>operationReturnType}}])
+
+{{/operation}}
+}
+
+{{/operations}}
diff --git a/modules/openapi-generator/src/main/resources/scala-sttp-client/apiInvoker.mustache b/modules/openapi-generator/src/main/resources/scala-sttp-client/apiInvoker.mustache
new file mode 100644
index 00000000000..254e92c74aa
--- /dev/null
+++ b/modules/openapi-generator/src/main/resources/scala-sttp-client/apiInvoker.mustache
@@ -0,0 +1,50 @@
+{{>licenseInfo}}
+package {{{mainPackage}}}.core
+
+import org.json4s._
+import sttp.client._
+import sttp.model.StatusCode
+import org.openapitools.client.api.EnumsSerializers
+import sttp.client.json4s.SttpJson4sApi
+import sttp.client.monad.MonadError
+
+class SttpSerializer(implicit val format: Formats = DefaultFormats ++ EnumsSerializers.all ++ Serializers.all,
+ implicit val serialization: org.json4s.Serialization = org.json4s.jackson.Serialization) extends SttpJson4sApi
+
+class HttpException(val statusCode: StatusCode, val statusText: String, val message: String) extends Exception(s"[$statusCode] $statusText: $message")
+
+object Helpers {
+
+ // Helper to handle Optional header parameters
+ implicit class optionalParams(val request: RequestT[Identity, Either[String, String], Nothing]) extends AnyVal {
+ def header( header: String, optValue: Option[Any]): RequestT[Identity, Either[String, String], Nothing] = {
+ optValue.map( value => request.header(header, value.toString)).getOrElse(request)
+ }
+ }
+
+}
+
+object ApiInvoker {
+
+ /**
+ * Allows request execution without calling apiInvoker.execute(request)
+ * request.result can be used to get a monad wrapped content.
+ *
+ * @param request the apiRequest to be executed
+ */
+ implicit class ApiRequestImprovements[R[_], T](request: RequestT[Identity, Either[ResponseError[Exception], T], Nothing]) {
+
+ def result(implicit backend: SttpBackend[R, Nothing, Nothing]): R[T] = {
+ val responseT = request.send()
+ val ME: MonadError[R] = backend.responseMonad
+ ME.flatMap(responseT) {
+ response =>
+ response.body match {
+ case Left(ex) => ME.error[T](new HttpException(response.code, response.statusText, ex.body))
+ case Right(value) => ME.unit(value)
+ }
+ }
+ }
+ }
+
+}
diff --git a/modules/openapi-generator/src/main/resources/scala-sttp-client/build.sbt.mustache b/modules/openapi-generator/src/main/resources/scala-sttp-client/build.sbt.mustache
new file mode 100644
index 00000000000..00fe48b731d
--- /dev/null
+++ b/modules/openapi-generator/src/main/resources/scala-sttp-client/build.sbt.mustache
@@ -0,0 +1,27 @@
+version := "{{artifactVersion}}"
+name := "{{artifactId}}"
+organization := "{{groupId}}"
+
+scalaVersion := "2.13.0"
+
+crossScalaVersions := Seq(scalaVersion.value, "2.12.10", "2.11.12")
+
+libraryDependencies ++= Seq(
+ "com.softwaremill.sttp.client" %% "core" % "2.0.0",
+ "com.softwaremill.sttp.client" %% "json4s" % "2.0.0",
+{{#joda}}
+ "joda-time" % "joda-time" % "2.10.1",
+{{/joda}}
+ "org.json4s" %% "json4s-jackson" % "3.6.7",
+ // test dependencies
+ "org.scalatest" %% "scalatest" % "3.0.8" % Test,
+ "junit" % "junit" % "4.13" % "test"
+)
+
+scalacOptions := Seq(
+ "-unchecked",
+ "-deprecation",
+ "-feature"
+)
+
+publishArtifact in (Compile, packageDoc) := false
\ No newline at end of file
diff --git a/modules/openapi-generator/src/main/resources/scala-sttp-client/enumsSerializers.mustache b/modules/openapi-generator/src/main/resources/scala-sttp-client/enumsSerializers.mustache
new file mode 100644
index 00000000000..8c7e6f2e41e
--- /dev/null
+++ b/modules/openapi-generator/src/main/resources/scala-sttp-client/enumsSerializers.mustache
@@ -0,0 +1,42 @@
+{{>licenseInfo}}
+package {{apiPackage}}
+
+{{#models.0}}
+import {{modelPackage}}._
+{{/models.0}}
+import org.json4s._
+import scala.reflect.ClassTag
+
+object EnumsSerializers {
+
+ def all: Seq[Serializer[_]] = Seq[Serializer[_]](){{#models}}{{#model}}{{#hasEnums}}{{#vars}}{{#isEnum}} :+
+ new EnumNameSerializer({{classname}}Enums.{{datatypeWithEnum}}){{/isEnum}}{{/vars}}{{/hasEnums}}{{/model}}{{/models}}
+
+ private class EnumNameSerializer[E <: Enumeration: ClassTag](enum: E)
+ extends Serializer[E#Value] {
+ import JsonDSL._
+
+ val EnumerationClass: Class[E#Value] = classOf[E#Value]
+
+ def deserialize(implicit format: Formats):
+ PartialFunction[(TypeInfo, JValue), E#Value] = {
+ case (t @ TypeInfo(EnumerationClass, _), json) if isValid(json) =>
+ json match {
+ case JString(value) =>
+ enum.withName(value)
+ case value =>
+ throw new MappingException(s"Can't convert $value to $EnumerationClass")
+ }
+ }
+
+ private[this] def isValid(json: JValue) = json match {
+ case JString(value) if enum.values.exists(_.toString == value) => true
+ case _ => false
+ }
+
+ def serialize(implicit format: Formats): PartialFunction[Any, JValue] = {
+ case i: E#Value => i.toString
+ }
+ }
+
+}
diff --git a/modules/openapi-generator/src/main/resources/scala-sttp-client/javadoc.mustache b/modules/openapi-generator/src/main/resources/scala-sttp-client/javadoc.mustache
new file mode 100644
index 00000000000..e42fa1dcdcd
--- /dev/null
+++ b/modules/openapi-generator/src/main/resources/scala-sttp-client/javadoc.mustache
@@ -0,0 +1,25 @@
+{{#notes}}
+{{{notes}}}
+
+{{/notes}}
+Expected answers:
+{{#responses}}
+ code {{code}} : {{{dataType}}} {{#message}}({{{message}}}){{/message}}
+ {{#headers}}
+ {{#-first}}
+ Headers :
+ {{/-first}}
+ {{{baseName}}} - {{{description}}}
+ {{/headers}}
+{{/responses}}
+{{#authMethods.0}}
+
+Available security schemes:
+{{#authMethods}}
+ {{name}} ({{type}})
+{{/authMethods}}
+{{/authMethods.0}}
+
+{{#allParams}}
+@param {{{paramName}}} {{{description}}}
+{{/allParams}}
diff --git a/modules/openapi-generator/src/main/resources/scala-sttp-client/licenseInfo.mustache b/modules/openapi-generator/src/main/resources/scala-sttp-client/licenseInfo.mustache
new file mode 100644
index 00000000000..835764cfc72
--- /dev/null
+++ b/modules/openapi-generator/src/main/resources/scala-sttp-client/licenseInfo.mustache
@@ -0,0 +1,11 @@
+/**
+ * {{{appName}}}
+ * {{{appDescription}}}
+ *
+ * {{#version}}The version of the OpenAPI document: {{{version}}}{{/version}}
+ * {{#infoEmail}}Contact: {{{infoEmail}}}{{/infoEmail}}
+ *
+ * NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech).
+ * https://openapi-generator.tech
+ * Do not edit the class manually.
+ */
\ No newline at end of file
diff --git a/modules/openapi-generator/src/main/resources/scala-sttp-client/methodParameters.mustache b/modules/openapi-generator/src/main/resources/scala-sttp-client/methodParameters.mustache
new file mode 100644
index 00000000000..54dc2f92a51
--- /dev/null
+++ b/modules/openapi-generator/src/main/resources/scala-sttp-client/methodParameters.mustache
@@ -0,0 +1 @@
+{{#allParams}}{{paramName}}: {{#required}}{{dataType}}{{/required}}{{^required}}{{#isContainer}}{{dataType}}{{/isContainer}}{{^isContainer}}Option[{{dataType}}]{{/isContainer}}{{/required}}{{^defaultValue}}{{^required}}{{^isContainer}} = None{{/isContainer}}{{/required}}{{/defaultValue}}{{#hasMore}}, {{/hasMore}}{{/allParams}}{{#authMethods.0}})(implicit {{#authMethods}}{{#isApiKey}}apiKey: ApiKeyValue{{/isApiKey}}{{#isBasic}}{{#isBasicBasic}}basicAuth: BasicCredentials{{/isBasicBasic}}{{#isBasicBearer}}bearerToken: BearerToken{{/isBasicBearer}}{{/isBasic}}{{#hasMore}}, {{/hasMore}}{{/authMethods}}{{/authMethods.0}}
\ No newline at end of file
diff --git a/modules/openapi-generator/src/main/resources/scala-sttp-client/model.mustache b/modules/openapi-generator/src/main/resources/scala-sttp-client/model.mustache
new file mode 100644
index 00000000000..941266f3306
--- /dev/null
+++ b/modules/openapi-generator/src/main/resources/scala-sttp-client/model.mustache
@@ -0,0 +1,50 @@
+{{>licenseInfo}}
+package {{package}}
+
+{{#imports}}
+import {{import}}
+{{/imports}}
+import {{mainPackage}}.core.ApiModel
+
+{{#models}}
+{{#model}}
+{{#description}}
+{{#javadocRenderer}}
+{{#title}}
+{{{title}}}
+{{/title}}
+{{{description}}}
+{{/javadocRenderer}}
+{{/description}}
+case class {{classname}}(
+ {{#vars}}
+ {{#description}}
+ /* {{{description}}} */
+ {{/description}}
+ {{{name}}}: {{^required}}Option[{{/required}}{{^isEnum}}{{dataType}}{{/isEnum}}{{#isEnum}}{{classname}}Enums.{{datatypeWithEnum}}{{/isEnum}}{{^required}}] = None{{/required}}{{#hasMore}},{{/hasMore}}
+ {{/vars}}
+) extends ApiModel
+
+{{#hasEnums}}
+object {{classname}}Enums {
+
+ {{#vars}}
+ {{#isEnum}}
+ type {{datatypeWithEnum}} = {{datatypeWithEnum}}.Value
+ {{/isEnum}}
+ {{/vars}}
+ {{#vars}}
+ {{#isEnum}}
+ object {{datatypeWithEnum}} extends Enumeration {
+{{#_enum}}
+ val {{#fnEnumEntry}}{{.}}{{/fnEnumEntry}} = Value("{{.}}")
+{{/_enum}}
+ }
+
+ {{/isEnum}}
+ {{/vars}}
+}
+{{/hasEnums}}
+{{/model}}
+{{/models}}
+
diff --git a/modules/openapi-generator/src/main/resources/scala-sttp-client/operationReturnType.mustache b/modules/openapi-generator/src/main/resources/scala-sttp-client/operationReturnType.mustache
new file mode 100644
index 00000000000..a8917911853
--- /dev/null
+++ b/modules/openapi-generator/src/main/resources/scala-sttp-client/operationReturnType.mustache
@@ -0,0 +1 @@
+{{#returnType}}{{{returnType}}}{{/returnType}}{{^returnType}}Unit{{/returnType}}
\ No newline at end of file
diff --git a/modules/openapi-generator/src/main/resources/scala-sttp-client/paramCreation.mustache b/modules/openapi-generator/src/main/resources/scala-sttp-client/paramCreation.mustache
new file mode 100644
index 00000000000..68280bd9a36
--- /dev/null
+++ b/modules/openapi-generator/src/main/resources/scala-sttp-client/paramCreation.mustache
@@ -0,0 +1 @@
+"{{baseName}}", {{#isContainer}}ArrayValues({{{paramName}}}{{#collectionFormat}}, {{collectionFormat.toUpperCase}}{{/collectionFormat}}){{/isContainer}}{{^isContainer}}{{{paramName}}}{{/isContainer}}
\ No newline at end of file
diff --git a/modules/openapi-generator/src/main/resources/scala-sttp-client/paramFormCreation.mustache b/modules/openapi-generator/src/main/resources/scala-sttp-client/paramFormCreation.mustache
new file mode 100644
index 00000000000..a0f1a65c074
--- /dev/null
+++ b/modules/openapi-generator/src/main/resources/scala-sttp-client/paramFormCreation.mustache
@@ -0,0 +1 @@
+"{{baseName}}" -> {{#isContainer}}ArrayValues({{{paramName}}}{{#collectionFormat}}, {{collectionFormat.toUpperCase}}{{/collectionFormat}}){{/isContainer}}{{^isContainer}}{{{paramName}}}{{/isContainer}}
\ No newline at end of file
diff --git a/modules/openapi-generator/src/main/resources/scala-sttp-client/paramQueryCreation.mustache b/modules/openapi-generator/src/main/resources/scala-sttp-client/paramQueryCreation.mustache
new file mode 100644
index 00000000000..8a1ea8cfcbf
--- /dev/null
+++ b/modules/openapi-generator/src/main/resources/scala-sttp-client/paramQueryCreation.mustache
@@ -0,0 +1 @@
+{{#isContainer}}${ formatQueryArray("{{{baseName}}}",{{{paramName}}}{{#collectionFormat}}, {{collectionFormat.toUpperCase}}{{/collectionFormat}}) }{{/isContainer}}{{^isContainer}}{{baseName}}=${ {{{paramName}}} }{{/isContainer}}
\ No newline at end of file
diff --git a/modules/openapi-generator/src/main/resources/scala-sttp-client/requests.mustache b/modules/openapi-generator/src/main/resources/scala-sttp-client/requests.mustache
new file mode 100644
index 00000000000..31158fd67cb
--- /dev/null
+++ b/modules/openapi-generator/src/main/resources/scala-sttp-client/requests.mustache
@@ -0,0 +1,48 @@
+{{>licenseInfo}}
+package {{mainPackage}}.core
+
+import sttp.client.{Identity, RequestT, ResponseError}
+
+/**
+ * This trait needs to be added to any model defined by the api.
+ */
+trait ApiModel
+
+/**
+ * Sttp type aliases
+ */
+object alias {
+ type ApiRequestT[T] = RequestT[Identity, Either[ResponseError[Exception], T], Nothing]
+}
+
+/**
+ * Single trait defining a credential that can be transformed to a paramName / paramValue tupple
+ */
+sealed trait Credentials {
+ def asQueryParam: Option[(String, String)] = None
+}
+
+sealed case class BasicCredentials(user: String, password: String) extends Credentials
+
+sealed case class BearerToken(token: String) extends Credentials
+
+sealed case class ApiKeyCredentials(key: ApiKeyValue, keyName: String, location: ApiKeyLocation) extends Credentials {
+ override def asQueryParam: Option[(String, String)] = location match {
+ case ApiKeyLocations.QUERY => Some((keyName, key.value))
+ case _ => None
+ }
+}
+
+sealed case class ApiKeyValue(value: String)
+
+sealed trait ApiKeyLocation
+
+object ApiKeyLocations {
+
+ case object QUERY extends ApiKeyLocation
+
+ case object HEADER extends ApiKeyLocation
+
+ case object COOKIE extends ApiKeyLocation
+
+}
diff --git a/modules/openapi-generator/src/main/resources/scala-sttp-client/responseState.mustache b/modules/openapi-generator/src/main/resources/scala-sttp-client/responseState.mustache
new file mode 100644
index 00000000000..d1b3798e6de
--- /dev/null
+++ b/modules/openapi-generator/src/main/resources/scala-sttp-client/responseState.mustache
@@ -0,0 +1 @@
+{{#isDefault}}Success{{/isDefault}}{{^isDefault}}Error{{/isDefault}}
\ No newline at end of file
diff --git a/modules/openapi-generator/src/main/resources/scala-sttp-client/serializers.mustache b/modules/openapi-generator/src/main/resources/scala-sttp-client/serializers.mustache
new file mode 100644
index 00000000000..a17d7706915
--- /dev/null
+++ b/modules/openapi-generator/src/main/resources/scala-sttp-client/serializers.mustache
@@ -0,0 +1,57 @@
+package {{invokerPackage}}
+
+{{#java8}}
+import java.time.{LocalDate, LocalDateTime, OffsetDateTime, ZoneId}
+import java.time.format.DateTimeFormatter
+import scala.util.Try
+{{/java8}}
+{{#joda}}
+import org.joda.time.DateTime
+import org.joda.time.format.ISODateTimeFormat
+{{/joda}}
+import org.json4s.{Serializer, CustomSerializer, JNull}
+import org.json4s.JsonAST.JString
+
+object Serializers {
+
+{{#java8}}
+ case object DateTimeSerializer extends CustomSerializer[OffsetDateTime](_ => ( {
+ case JString(s) =>
+ Try(OffsetDateTime.parse(s, DateTimeFormatter.ISO_OFFSET_DATE_TIME)) orElse
+ Try(LocalDateTime.parse(s).atZone(ZoneId.systemDefault()).toOffsetDateTime) getOrElse (null)
+ case JNull => null
+ }, {
+ case d: OffsetDateTime =>
+ JString(d.format(DateTimeFormatter.ISO_OFFSET_DATE_TIME))
+ }))
+
+ case object LocalDateSerializer extends CustomSerializer[LocalDate]( _ => ( {
+ case JString(s) => LocalDate.parse(s)
+ case JNull => null
+ }, {
+ case d: LocalDate =>
+ JString(d.format(DateTimeFormatter.ISO_LOCAL_DATE))
+ }))
+{{/java8}}
+{{#joda}}
+ case object DateTimeSerializer extends CustomSerializer[DateTime](_ => ( {
+ case JString(s) =>
+ ISODateTimeFormat.dateOptionalTimeParser().parseDateTime(s)
+ case JNull => null
+ }, {
+ case d: org.joda.time.DateTime =>
+ JString(ISODateTimeFormat.dateTime().print(d))
+ })
+ )
+
+ case object LocalDateSerializer extends CustomSerializer[org.joda.time.LocalDate](_ => ( {
+ case JString(s) => org.joda.time.format.DateTimeFormat.forPattern("yyyy-MM-dd").parseLocalDate(s)
+ case JNull => null
+ }, {
+ case d: org.joda.time.LocalDate => JString(d.toString("yyyy-MM-dd"))
+ }))
+{{/joda}}
+
+ def all: Seq[Serializer[_]] = Seq[Serializer[_]]() :+ LocalDateSerializer :+ DateTimeSerializer
+
+}
diff --git a/samples/client/petstore/scala-sttp/.openapi-generator-ignore b/samples/client/petstore/scala-sttp/.openapi-generator-ignore
new file mode 100644
index 00000000000..7484ee590a3
--- /dev/null
+++ b/samples/client/petstore/scala-sttp/.openapi-generator-ignore
@@ -0,0 +1,23 @@
+# OpenAPI Generator Ignore
+# Generated by openapi-generator https://github.com/openapitools/openapi-generator
+
+# 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 OpenAPI Generator 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/scala-sttp/.openapi-generator/VERSION b/samples/client/petstore/scala-sttp/.openapi-generator/VERSION
new file mode 100644
index 00000000000..bfbf77eb7fa
--- /dev/null
+++ b/samples/client/petstore/scala-sttp/.openapi-generator/VERSION
@@ -0,0 +1 @@
+4.3.0-SNAPSHOT
\ No newline at end of file
diff --git a/samples/client/petstore/scala-sttp/README.md b/samples/client/petstore/scala-sttp/README.md
new file mode 100644
index 00000000000..b3d417a26fe
--- /dev/null
+++ b/samples/client/petstore/scala-sttp/README.md
@@ -0,0 +1,121 @@
+# scala-sttp-petstore-client
+
+OpenAPI Petstore
+- API version: 1.0.0
+
+This is a sample server Petstore server. For this sample, you can use the api key `special-key` to test the authorization filters.
+
+
+*Automatically generated by the [OpenAPI Generator](https://openapi-generator.tech)*
+
+## Requirements
+
+Building the API client library requires:
+1. Java 1.7+
+2. Maven/Gradle/SBT
+
+## Installation
+
+To install the API client library to your local Maven repository, simply execute:
+
+```shell
+mvn clean install
+```
+
+To deploy it to a remote Maven repository instead, configure the settings of the repository and execute:
+
+```shell
+mvn clean deploy
+```
+
+Refer to the [OSSRH Guide](http://central.sonatype.org/pages/ossrh-guide.html) for more information.
+
+### Maven users
+
+Add this dependency to your project's POM:
+
+```xml
+
+ org.openapitools
+ scala-sttp-petstore-client
+ 1.0.0
+ compile
+
+```
+
+### Gradle users
+
+Add this dependency to your project's build file:
+
+```groovy
+compile "org.openapitools:scala-sttp-petstore-client:1.0.0"
+```
+
+### SBT users
+
+```scala
+libraryDependencies += "org.openapitools" % "scala-sttp-petstore-client" % "1.0.0"
+```
+
+## Getting Started
+
+## Documentation for API Endpoints
+
+All URIs are relative to *http://petstore.swagger.io/v2*
+
+Class | Method | HTTP request | Description
+------------ | ------------- | ------------- | -------------
+*PetApi* | **addPet** | **POST** /pet | Add a new pet to the store
+*PetApi* | **deletePet** | **DELETE** /pet/${petId} | Deletes a pet
+*PetApi* | **findPetsByStatus** | **GET** /pet/findByStatus | Finds Pets by status
+*PetApi* | **findPetsByTags** | **GET** /pet/findByTags | Finds Pets by tags
+*PetApi* | **getPetById** | **GET** /pet/${petId} | Find pet by ID
+*PetApi* | **updatePet** | **PUT** /pet | Update an existing pet
+*PetApi* | **updatePetWithForm** | **POST** /pet/${petId} | Updates a pet in the store with form data
+*PetApi* | **uploadFile** | **POST** /pet/${petId}/uploadImage | uploads an image
+*StoreApi* | **deleteOrder** | **DELETE** /store/order/${orderId} | Delete purchase order by ID
+*StoreApi* | **getInventory** | **GET** /store/inventory | Returns pet inventories by status
+*StoreApi* | **getOrderById** | **GET** /store/order/${orderId} | Find purchase order by ID
+*StoreApi* | **placeOrder** | **POST** /store/order | Place an order for a pet
+*UserApi* | **createUser** | **POST** /user | Create user
+*UserApi* | **createUsersWithArrayInput** | **POST** /user/createWithArray | Creates list of users with given input array
+*UserApi* | **createUsersWithListInput** | **POST** /user/createWithList | Creates list of users with given input array
+*UserApi* | **deleteUser** | **DELETE** /user/${username} | Delete user
+*UserApi* | **getUserByName** | **GET** /user/${username} | Get user by user name
+*UserApi* | **loginUser** | **GET** /user/login | Logs user into the system
+*UserApi* | **logoutUser** | **GET** /user/logout | Logs out current logged in user session
+*UserApi* | **updateUser** | **PUT** /user/${username} | Updated user
+
+
+## Documentation for Models
+
+ - [ApiResponse](ApiResponse.md)
+ - [Category](Category.md)
+ - [InlineObject](InlineObject.md)
+ - [InlineObject1](InlineObject1.md)
+ - [Order](Order.md)
+ - [Pet](Pet.md)
+ - [Tag](Tag.md)
+ - [User](User.md)
+
+
+## Documentation for Authorization
+
+Authentication schemes defined for the API:
+### api_key
+
+- **Type**: API key
+- **API key parameter name**: api_key
+- **Location**: HTTP header
+
+### auth_cookie
+
+- **Type**: API key
+- **API key parameter name**: AUTH_KEY
+- **Location**:
+
+
+## Author
+
+
+
diff --git a/samples/client/petstore/scala-sttp/build.sbt b/samples/client/petstore/scala-sttp/build.sbt
new file mode 100644
index 00000000000..6964f664a1d
--- /dev/null
+++ b/samples/client/petstore/scala-sttp/build.sbt
@@ -0,0 +1,25 @@
+version := "1.0.0"
+name := "scala-sttp-petstore-client"
+organization := "org.openapitools"
+
+scalaVersion := "2.13.0"
+
+crossScalaVersions := Seq(scalaVersion.value, "2.12.10", "2.11.12")
+
+libraryDependencies ++= Seq(
+ "com.softwaremill.sttp.client" %% "core" % "2.0.0",
+ "com.softwaremill.sttp.client" %% "json4s" % "2.0.0",
+ "joda-time" % "joda-time" % "2.10.1",
+ "org.json4s" %% "json4s-jackson" % "3.6.7",
+ // test dependencies
+ "org.scalatest" %% "scalatest" % "3.0.8" % Test,
+ "junit" % "junit" % "4.13" % "test"
+)
+
+scalacOptions := Seq(
+ "-unchecked",
+ "-deprecation",
+ "-feature"
+)
+
+publishArtifact in (Compile, packageDoc) := false
\ No newline at end of file
diff --git a/samples/client/petstore/scala-sttp/project/build.properties b/samples/client/petstore/scala-sttp/project/build.properties
new file mode 100644
index 00000000000..c0bab04941d
--- /dev/null
+++ b/samples/client/petstore/scala-sttp/project/build.properties
@@ -0,0 +1 @@
+sbt.version=1.2.8
diff --git a/samples/client/petstore/scala-sttp/src/main/scala/org/openapitools/client/api/EnumsSerializers.scala b/samples/client/petstore/scala-sttp/src/main/scala/org/openapitools/client/api/EnumsSerializers.scala
new file mode 100644
index 00000000000..71ad618e31f
--- /dev/null
+++ b/samples/client/petstore/scala-sttp/src/main/scala/org/openapitools/client/api/EnumsSerializers.scala
@@ -0,0 +1,51 @@
+/**
+ * OpenAPI Petstore
+ * This is a sample server Petstore server. For this sample, you can use the api key `special-key` to test the authorization filters.
+ *
+ * The version of the OpenAPI document: 1.0.0
+ *
+ *
+ * NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech).
+ * https://openapi-generator.tech
+ * Do not edit the class manually.
+ */
+package org.openapitools.client.api
+
+import org.openapitools.client.model._
+import org.json4s._
+import scala.reflect.ClassTag
+
+object EnumsSerializers {
+
+ def all: Seq[Serializer[_]] = Seq[Serializer[_]]() :+
+ new EnumNameSerializer(OrderEnums.Status) :+
+ new EnumNameSerializer(PetEnums.Status)
+
+ private class EnumNameSerializer[E <: Enumeration: ClassTag](enum: E)
+ extends Serializer[E#Value] {
+ import JsonDSL._
+
+ val EnumerationClass: Class[E#Value] = classOf[E#Value]
+
+ def deserialize(implicit format: Formats):
+ PartialFunction[(TypeInfo, JValue), E#Value] = {
+ case (t @ TypeInfo(EnumerationClass, _), json) if isValid(json) =>
+ json match {
+ case JString(value) =>
+ enum.withName(value)
+ case value =>
+ throw new MappingException(s"Can't convert $value to $EnumerationClass")
+ }
+ }
+
+ private[this] def isValid(json: JValue) = json match {
+ case JString(value) if enum.values.exists(_.toString == value) => true
+ case _ => false
+ }
+
+ def serialize(implicit format: Formats): PartialFunction[Any, JValue] = {
+ case i: E#Value => i.toString
+ }
+ }
+
+}
diff --git a/samples/client/petstore/scala-sttp/src/main/scala/org/openapitools/client/api/PetApi.scala b/samples/client/petstore/scala-sttp/src/main/scala/org/openapitools/client/api/PetApi.scala
new file mode 100644
index 00000000000..5211d09c9c5
--- /dev/null
+++ b/samples/client/petstore/scala-sttp/src/main/scala/org/openapitools/client/api/PetApi.scala
@@ -0,0 +1,163 @@
+/**
+ * OpenAPI Petstore
+ * This is a sample server Petstore server. For this sample, you can use the api key `special-key` to test the authorization filters.
+ *
+ * The version of the OpenAPI document: 1.0.0
+ *
+ *
+ * NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech).
+ * https://openapi-generator.tech
+ * Do not edit the class manually.
+ */
+package org.openapitools.client.api
+
+import org.openapitools.client.model.ApiResponse
+import java.io.File
+import org.openapitools.client.model.Pet
+import org.openapitools.client.core._
+import alias._
+import sttp.client._
+import sttp.model.Method
+
+object PetApi {
+
+ def apply(baseUrl: String = "http://petstore.swagger.io/v2")(implicit serializer: SttpSerializer) = new PetApi(baseUrl)
+}
+
+class PetApi(baseUrl: String)(implicit serializer: SttpSerializer) {
+
+ import Helpers._
+ import serializer._
+
+ /**
+ * Expected answers:
+ * code 200 : Pet (successful operation)
+ * code 405 : (Invalid input)
+ *
+ * @param pet Pet object that needs to be added to the store
+ */
+ def addPet(pet: Pet): ApiRequestT[Pet] =
+ basicRequest
+ .method(Method.POST, uri"$baseUrl/pet")
+ .contentType("application/json")
+ .body(pet)
+ .response(asJson[Pet])
+
+ /**
+ * Expected answers:
+ * code 400 : (Invalid pet value)
+ *
+ * @param petId Pet id to delete
+ * @param apiKey
+ */
+ def deletePet(petId: Long, apiKey: Option[String] = None): ApiRequestT[Unit] =
+ basicRequest
+ .method(Method.DELETE, uri"$baseUrl/pet/${petId}")
+ .contentType("application/json")
+ .header("api_key", apiKey)
+ .response(asJson[Unit])
+
+ /**
+ * Multiple status values can be provided with comma separated strings
+ *
+ * Expected answers:
+ * code 200 : Seq[Pet] (successful operation)
+ * code 400 : (Invalid status value)
+ *
+ * @param status Status values that need to be considered for filter
+ */
+ def findPetsByStatus(status: Seq[String]): ApiRequestT[Seq[Pet]] =
+ basicRequest
+ .method(Method.GET, uri"$baseUrl/pet/findByStatus?status=$status")
+ .contentType("application/json")
+ .response(asJson[Seq[Pet]])
+
+ /**
+ * Multiple tags can be provided with comma separated strings. Use tag1, tag2, tag3 for testing.
+ *
+ * Expected answers:
+ * code 200 : Seq[Pet] (successful operation)
+ * code 400 : (Invalid tag value)
+ *
+ * @param tags Tags to filter by
+ */
+ def findPetsByTags(tags: Seq[String]): ApiRequestT[Seq[Pet]] =
+ basicRequest
+ .method(Method.GET, uri"$baseUrl/pet/findByTags?tags=$tags")
+ .contentType("application/json")
+ .response(asJson[Seq[Pet]])
+
+ /**
+ * Returns a single pet
+ *
+ * Expected answers:
+ * code 200 : Pet (successful operation)
+ * code 400 : (Invalid ID supplied)
+ * code 404 : (Pet not found)
+ *
+ * Available security schemes:
+ * api_key (apiKey)
+ *
+ * @param petId ID of pet to return
+ */
+ def getPetById(petId: Long)(implicit apiKey: ApiKeyValue): ApiRequestT[Pet] =
+ basicRequest
+ .method(Method.GET, uri"$baseUrl/pet/${petId}")
+ .contentType("application/json")
+ .header("api_key", apiKey.value)
+ .response(asJson[Pet])
+
+ /**
+ * Expected answers:
+ * code 200 : Pet (successful operation)
+ * code 400 : (Invalid ID supplied)
+ * code 404 : (Pet not found)
+ * code 405 : (Validation exception)
+ *
+ * @param pet Pet object that needs to be added to the store
+ */
+ def updatePet(pet: Pet): ApiRequestT[Pet] =
+ basicRequest
+ .method(Method.PUT, uri"$baseUrl/pet")
+ .contentType("application/json")
+ .body(pet)
+ .response(asJson[Pet])
+
+ /**
+ * Expected answers:
+ * code 405 : (Invalid input)
+ *
+ * @param petId ID of pet that needs to be updated
+ * @param name Updated name of the pet
+ * @param status Updated status of the pet
+ */
+ def updatePetWithForm(petId: Long, name: Option[String] = None, status: Option[String] = None): ApiRequestT[Unit] =
+ basicRequest
+ .method(Method.POST, uri"$baseUrl/pet/${petId}")
+ .contentType("application/x-www-form-urlencoded")
+ .body(Map(
+ "name" -> name,
+ "status" -> status,
+ ))
+ .response(asJson[Unit])
+
+ /**
+ * Expected answers:
+ * code 200 : ApiResponse (successful operation)
+ *
+ * @param petId ID of pet to update
+ * @param additionalMetadata Additional data to pass to server
+ * @param file file to upload
+ */
+ def uploadFile(petId: Long, additionalMetadata: Option[String] = None, file: Option[File] = None): ApiRequestT[ApiResponse] =
+ basicRequest
+ .method(Method.POST, uri"$baseUrl/pet/${petId}/uploadImage")
+ .contentType("multipart/form-data")
+ .body(Map(
+ "additionalMetadata" -> additionalMetadata,
+ "file" -> file,
+ ))
+ .response(asJson[ApiResponse])
+
+}
+
diff --git a/samples/client/petstore/scala-sttp/src/main/scala/org/openapitools/client/api/StoreApi.scala b/samples/client/petstore/scala-sttp/src/main/scala/org/openapitools/client/api/StoreApi.scala
new file mode 100644
index 00000000000..907cc9f42f0
--- /dev/null
+++ b/samples/client/petstore/scala-sttp/src/main/scala/org/openapitools/client/api/StoreApi.scala
@@ -0,0 +1,92 @@
+/**
+ * OpenAPI Petstore
+ * This is a sample server Petstore server. For this sample, you can use the api key `special-key` to test the authorization filters.
+ *
+ * The version of the OpenAPI document: 1.0.0
+ *
+ *
+ * NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech).
+ * https://openapi-generator.tech
+ * Do not edit the class manually.
+ */
+package org.openapitools.client.api
+
+import org.openapitools.client.model.Order
+import org.openapitools.client.core._
+import alias._
+import sttp.client._
+import sttp.model.Method
+
+object StoreApi {
+
+ def apply(baseUrl: String = "http://petstore.swagger.io/v2")(implicit serializer: SttpSerializer) = new StoreApi(baseUrl)
+}
+
+class StoreApi(baseUrl: String)(implicit serializer: SttpSerializer) {
+
+ import Helpers._
+ import serializer._
+
+ /**
+ * For valid response try integer IDs with value < 1000. Anything above 1000 or nonintegers will generate API errors
+ *
+ * Expected answers:
+ * code 400 : (Invalid ID supplied)
+ * code 404 : (Order not found)
+ *
+ * @param orderId ID of the order that needs to be deleted
+ */
+ def deleteOrder(orderId: String): ApiRequestT[Unit] =
+ basicRequest
+ .method(Method.DELETE, uri"$baseUrl/store/order/${orderId}")
+ .contentType("application/json")
+ .response(asJson[Unit])
+
+ /**
+ * Returns a map of status codes to quantities
+ *
+ * Expected answers:
+ * code 200 : Map[String, Int] (successful operation)
+ *
+ * Available security schemes:
+ * api_key (apiKey)
+ */
+ def getInventory()(implicit apiKey: ApiKeyValue): ApiRequestT[Map[String, Int]] =
+ basicRequest
+ .method(Method.GET, uri"$baseUrl/store/inventory")
+ .contentType("application/json")
+ .header("api_key", apiKey.value)
+ .response(asJson[Map[String, Int]])
+
+ /**
+ * For valid response try integer IDs with value <= 5 or > 10. Other values will generated exceptions
+ *
+ * Expected answers:
+ * code 200 : Order (successful operation)
+ * code 400 : (Invalid ID supplied)
+ * code 404 : (Order not found)
+ *
+ * @param orderId ID of pet that needs to be fetched
+ */
+ def getOrderById(orderId: Long): ApiRequestT[Order] =
+ basicRequest
+ .method(Method.GET, uri"$baseUrl/store/order/${orderId}")
+ .contentType("application/json")
+ .response(asJson[Order])
+
+ /**
+ * Expected answers:
+ * code 200 : Order (successful operation)
+ * code 400 : (Invalid Order)
+ *
+ * @param order order placed for purchasing the pet
+ */
+ def placeOrder(order: Order): ApiRequestT[Order] =
+ basicRequest
+ .method(Method.POST, uri"$baseUrl/store/order")
+ .contentType("application/json")
+ .body(order)
+ .response(asJson[Order])
+
+}
+
diff --git a/samples/client/petstore/scala-sttp/src/main/scala/org/openapitools/client/api/UserApi.scala b/samples/client/petstore/scala-sttp/src/main/scala/org/openapitools/client/api/UserApi.scala
new file mode 100644
index 00000000000..7b7df3b8e14
--- /dev/null
+++ b/samples/client/petstore/scala-sttp/src/main/scala/org/openapitools/client/api/UserApi.scala
@@ -0,0 +1,170 @@
+/**
+ * OpenAPI Petstore
+ * This is a sample server Petstore server. For this sample, you can use the api key `special-key` to test the authorization filters.
+ *
+ * The version of the OpenAPI document: 1.0.0
+ *
+ *
+ * NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech).
+ * https://openapi-generator.tech
+ * Do not edit the class manually.
+ */
+package org.openapitools.client.api
+
+import org.openapitools.client.model.User
+import org.openapitools.client.core._
+import alias._
+import sttp.client._
+import sttp.model.Method
+
+object UserApi {
+
+ def apply(baseUrl: String = "http://petstore.swagger.io/v2")(implicit serializer: SttpSerializer) = new UserApi(baseUrl)
+}
+
+class UserApi(baseUrl: String)(implicit serializer: SttpSerializer) {
+
+ import Helpers._
+ import serializer._
+
+ /**
+ * This can only be done by the logged in user.
+ *
+ * Expected answers:
+ * code 0 : (successful operation)
+ *
+ * Available security schemes:
+ * auth_cookie (apiKey)
+ *
+ * @param user Created user object
+ */
+ def createUser(user: User)(implicit apiKey: ApiKeyValue): ApiRequestT[Unit] =
+ basicRequest
+ .method(Method.POST, uri"$baseUrl/user")
+ .contentType("application/json")
+ .cookie("AUTH_KEY", apiKey.value)
+ .body(user)
+ .response(asJson[Unit])
+
+ /**
+ * Expected answers:
+ * code 0 : (successful operation)
+ *
+ * Available security schemes:
+ * auth_cookie (apiKey)
+ *
+ * @param user List of user object
+ */
+ def createUsersWithArrayInput(user: Seq[User])(implicit apiKey: ApiKeyValue): ApiRequestT[Unit] =
+ basicRequest
+ .method(Method.POST, uri"$baseUrl/user/createWithArray")
+ .contentType("application/json")
+ .cookie("AUTH_KEY", apiKey.value)
+ .body(user)
+ .response(asJson[Unit])
+
+ /**
+ * Expected answers:
+ * code 0 : (successful operation)
+ *
+ * Available security schemes:
+ * auth_cookie (apiKey)
+ *
+ * @param user List of user object
+ */
+ def createUsersWithListInput(user: Seq[User])(implicit apiKey: ApiKeyValue): ApiRequestT[Unit] =
+ basicRequest
+ .method(Method.POST, uri"$baseUrl/user/createWithList")
+ .contentType("application/json")
+ .cookie("AUTH_KEY", apiKey.value)
+ .body(user)
+ .response(asJson[Unit])
+
+ /**
+ * This can only be done by the logged in user.
+ *
+ * Expected answers:
+ * code 400 : (Invalid username supplied)
+ * code 404 : (User not found)
+ *
+ * Available security schemes:
+ * auth_cookie (apiKey)
+ *
+ * @param username The name that needs to be deleted
+ */
+ def deleteUser(username: String)(implicit apiKey: ApiKeyValue): ApiRequestT[Unit] =
+ basicRequest
+ .method(Method.DELETE, uri"$baseUrl/user/${username}")
+ .contentType("application/json")
+ .cookie("AUTH_KEY", apiKey.value)
+ .response(asJson[Unit])
+
+ /**
+ * Expected answers:
+ * code 200 : User (successful operation)
+ * code 400 : (Invalid username supplied)
+ * code 404 : (User not found)
+ *
+ * @param username The name that needs to be fetched. Use user1 for testing.
+ */
+ def getUserByName(username: String): ApiRequestT[User] =
+ basicRequest
+ .method(Method.GET, uri"$baseUrl/user/${username}")
+ .contentType("application/json")
+ .response(asJson[User])
+
+ /**
+ * Expected answers:
+ * code 200 : String (successful operation)
+ * Headers :
+ * Set-Cookie - Cookie authentication key for use with the `auth_cookie` apiKey authentication.
+ * X-Rate-Limit - calls per hour allowed by the user
+ * X-Expires-After - date in UTC when toekn expires
+ * code 400 : (Invalid username/password supplied)
+ *
+ * @param username The user name for login
+ * @param password The password for login in clear text
+ */
+ def loginUser(username: String, password: String): ApiRequestT[String] =
+ basicRequest
+ .method(Method.GET, uri"$baseUrl/user/login?username=$username&password=$password")
+ .contentType("application/json")
+ .response(asJson[String])
+
+ /**
+ * Expected answers:
+ * code 0 : (successful operation)
+ *
+ * Available security schemes:
+ * auth_cookie (apiKey)
+ */
+ def logoutUser()(implicit apiKey: ApiKeyValue): ApiRequestT[Unit] =
+ basicRequest
+ .method(Method.GET, uri"$baseUrl/user/logout")
+ .contentType("application/json")
+ .cookie("AUTH_KEY", apiKey.value)
+ .response(asJson[Unit])
+
+ /**
+ * This can only be done by the logged in user.
+ *
+ * Expected answers:
+ * code 400 : (Invalid user supplied)
+ * code 404 : (User not found)
+ *
+ * Available security schemes:
+ * auth_cookie (apiKey)
+ *
+ * @param username name that need to be deleted
+ * @param user Updated user object
+ */
+ def updateUser(username: String, user: User)(implicit apiKey: ApiKeyValue): ApiRequestT[Unit] =
+ basicRequest
+ .method(Method.PUT, uri"$baseUrl/user/${username}")
+ .contentType("application/json")
+ .cookie("AUTH_KEY", apiKey.value)
+ .body(user)
+ .response(asJson[Unit])
+
+}
+
diff --git a/samples/client/petstore/scala-sttp/src/main/scala/org/openapitools/client/core/ApiInvoker.scala b/samples/client/petstore/scala-sttp/src/main/scala/org/openapitools/client/core/ApiInvoker.scala
new file mode 100644
index 00000000000..dc98ff4d136
--- /dev/null
+++ b/samples/client/petstore/scala-sttp/src/main/scala/org/openapitools/client/core/ApiInvoker.scala
@@ -0,0 +1,60 @@
+/**
+ * OpenAPI Petstore
+ * This is a sample server Petstore server. For this sample, you can use the api key `special-key` to test the authorization filters.
+ *
+ * The version of the OpenAPI document: 1.0.0
+ *
+ *
+ * NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech).
+ * https://openapi-generator.tech
+ * Do not edit the class manually.
+ */
+package org.openapitools.client.core
+
+import org.json4s._
+import sttp.client._
+import sttp.model.StatusCode
+import org.openapitools.client.api.EnumsSerializers
+import sttp.client.json4s.SttpJson4sApi
+import sttp.client.monad.MonadError
+
+class SttpSerializer(implicit val format: Formats = DefaultFormats ++ EnumsSerializers.all ++ Serializers.all,
+ implicit val serialization: org.json4s.Serialization = org.json4s.jackson.Serialization) extends SttpJson4sApi
+
+class HttpException(val statusCode: StatusCode, val statusText: String, val message: String) extends Exception(s"[$statusCode] $statusText: $message")
+
+object Helpers {
+
+ // Helper to handle Optional header parameters
+ implicit class optionalParams(val request: RequestT[Identity, Either[String, String], Nothing]) extends AnyVal {
+ def header( header: String, optValue: Option[Any]): RequestT[Identity, Either[String, String], Nothing] = {
+ optValue.map( value => request.header(header, value.toString)).getOrElse(request)
+ }
+ }
+
+}
+
+object ApiInvoker {
+
+ /**
+ * Allows request execution without calling apiInvoker.execute(request)
+ * request.result can be used to get a monad wrapped content.
+ *
+ * @param request the apiRequest to be executed
+ */
+ implicit class ApiRequestImprovements[R[_], T](request: RequestT[Identity, Either[ResponseError[Exception], T], Nothing]) {
+
+ def result(implicit backend: SttpBackend[R, Nothing, Nothing]): R[T] = {
+ val responseT = request.send()
+ val ME: MonadError[R] = backend.responseMonad
+ ME.flatMap(responseT) {
+ response =>
+ response.body match {
+ case Left(ex) => ME.error[T](new HttpException(response.code, response.statusText, ex.body))
+ case Right(value) => ME.unit(value)
+ }
+ }
+ }
+ }
+
+}
diff --git a/samples/client/petstore/scala-sttp/src/main/scala/org/openapitools/client/core/Serializers.scala b/samples/client/petstore/scala-sttp/src/main/scala/org/openapitools/client/core/Serializers.scala
new file mode 100644
index 00000000000..80188ba5e6a
--- /dev/null
+++ b/samples/client/petstore/scala-sttp/src/main/scala/org/openapitools/client/core/Serializers.scala
@@ -0,0 +1,29 @@
+package org.openapitools.client.core
+
+import org.joda.time.DateTime
+import org.joda.time.format.ISODateTimeFormat
+import org.json4s.{Serializer, CustomSerializer, JNull}
+import org.json4s.JsonAST.JString
+
+object Serializers {
+
+ case object DateTimeSerializer extends CustomSerializer[DateTime](_ => ( {
+ case JString(s) =>
+ ISODateTimeFormat.dateOptionalTimeParser().parseDateTime(s)
+ case JNull => null
+ }, {
+ case d: org.joda.time.DateTime =>
+ JString(ISODateTimeFormat.dateTime().print(d))
+ })
+ )
+
+ case object LocalDateSerializer extends CustomSerializer[org.joda.time.LocalDate](_ => ( {
+ case JString(s) => org.joda.time.format.DateTimeFormat.forPattern("yyyy-MM-dd").parseLocalDate(s)
+ case JNull => null
+ }, {
+ case d: org.joda.time.LocalDate => JString(d.toString("yyyy-MM-dd"))
+ }))
+
+ def all: Seq[Serializer[_]] = Seq[Serializer[_]]() :+ LocalDateSerializer :+ DateTimeSerializer
+
+}
diff --git a/samples/client/petstore/scala-sttp/src/main/scala/org/openapitools/client/core/requests.scala b/samples/client/petstore/scala-sttp/src/main/scala/org/openapitools/client/core/requests.scala
new file mode 100644
index 00000000000..1f45be8103e
--- /dev/null
+++ b/samples/client/petstore/scala-sttp/src/main/scala/org/openapitools/client/core/requests.scala
@@ -0,0 +1,58 @@
+/**
+ * OpenAPI Petstore
+ * This is a sample server Petstore server. For this sample, you can use the api key `special-key` to test the authorization filters.
+ *
+ * The version of the OpenAPI document: 1.0.0
+ *
+ *
+ * NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech).
+ * https://openapi-generator.tech
+ * Do not edit the class manually.
+ */
+package org.openapitools.client.core
+
+import sttp.client.{Identity, RequestT, ResponseError}
+
+/**
+ * This trait needs to be added to any model defined by the api.
+ */
+trait ApiModel
+
+/**
+ * Sttp type aliases
+ */
+object alias {
+ type ApiRequestT[T] = RequestT[Identity, Either[ResponseError[Exception], T], Nothing]
+}
+
+/**
+ * Single trait defining a credential that can be transformed to a paramName / paramValue tupple
+ */
+sealed trait Credentials {
+ def asQueryParam: Option[(String, String)] = None
+}
+
+sealed case class BasicCredentials(user: String, password: String) extends Credentials
+
+sealed case class BearerToken(token: String) extends Credentials
+
+sealed case class ApiKeyCredentials(key: ApiKeyValue, keyName: String, location: ApiKeyLocation) extends Credentials {
+ override def asQueryParam: Option[(String, String)] = location match {
+ case ApiKeyLocations.QUERY => Some((keyName, key.value))
+ case _ => None
+ }
+}
+
+sealed case class ApiKeyValue(value: String)
+
+sealed trait ApiKeyLocation
+
+object ApiKeyLocations {
+
+ case object QUERY extends ApiKeyLocation
+
+ case object HEADER extends ApiKeyLocation
+
+ case object COOKIE extends ApiKeyLocation
+
+}
diff --git a/samples/client/petstore/scala-sttp/src/main/scala/org/openapitools/client/model/ApiResponse.scala b/samples/client/petstore/scala-sttp/src/main/scala/org/openapitools/client/model/ApiResponse.scala
new file mode 100644
index 00000000000..3a3b6d6f499
--- /dev/null
+++ b/samples/client/petstore/scala-sttp/src/main/scala/org/openapitools/client/model/ApiResponse.scala
@@ -0,0 +1,26 @@
+/**
+ * OpenAPI Petstore
+ * This is a sample server Petstore server. For this sample, you can use the api key `special-key` to test the authorization filters.
+ *
+ * The version of the OpenAPI document: 1.0.0
+ *
+ *
+ * NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech).
+ * https://openapi-generator.tech
+ * Do not edit the class manually.
+ */
+package org.openapitools.client.model
+
+import org.openapitools.client.core.ApiModel
+
+ /**
+ * An uploaded response
+ * Describes the result of uploading an image resource
+ */
+case class ApiResponse(
+ code: Option[Int] = None,
+ `type`: Option[String] = None,
+ message: Option[String] = None
+) extends ApiModel
+
+
diff --git a/samples/client/petstore/scala-sttp/src/main/scala/org/openapitools/client/model/Category.scala b/samples/client/petstore/scala-sttp/src/main/scala/org/openapitools/client/model/Category.scala
new file mode 100644
index 00000000000..011164617cf
--- /dev/null
+++ b/samples/client/petstore/scala-sttp/src/main/scala/org/openapitools/client/model/Category.scala
@@ -0,0 +1,25 @@
+/**
+ * OpenAPI Petstore
+ * This is a sample server Petstore server. For this sample, you can use the api key `special-key` to test the authorization filters.
+ *
+ * The version of the OpenAPI document: 1.0.0
+ *
+ *
+ * NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech).
+ * https://openapi-generator.tech
+ * Do not edit the class manually.
+ */
+package org.openapitools.client.model
+
+import org.openapitools.client.core.ApiModel
+
+ /**
+ * Pet category
+ * A category for a pet
+ */
+case class Category(
+ id: Option[Long] = None,
+ name: Option[String] = None
+) extends ApiModel
+
+
diff --git a/samples/client/petstore/scala-sttp/src/main/scala/org/openapitools/client/model/InlineObject.scala b/samples/client/petstore/scala-sttp/src/main/scala/org/openapitools/client/model/InlineObject.scala
new file mode 100644
index 00000000000..a8c5493161a
--- /dev/null
+++ b/samples/client/petstore/scala-sttp/src/main/scala/org/openapitools/client/model/InlineObject.scala
@@ -0,0 +1,23 @@
+/**
+ * OpenAPI Petstore
+ * This is a sample server Petstore server. For this sample, you can use the api key `special-key` to test the authorization filters.
+ *
+ * The version of the OpenAPI document: 1.0.0
+ *
+ *
+ * NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech).
+ * https://openapi-generator.tech
+ * Do not edit the class manually.
+ */
+package org.openapitools.client.model
+
+import org.openapitools.client.core.ApiModel
+
+case class InlineObject(
+ /* Updated name of the pet */
+ name: Option[String] = None,
+ /* Updated status of the pet */
+ status: Option[String] = None
+) extends ApiModel
+
+
diff --git a/samples/client/petstore/scala-sttp/src/main/scala/org/openapitools/client/model/InlineObject1.scala b/samples/client/petstore/scala-sttp/src/main/scala/org/openapitools/client/model/InlineObject1.scala
new file mode 100644
index 00000000000..480cf8c2e10
--- /dev/null
+++ b/samples/client/petstore/scala-sttp/src/main/scala/org/openapitools/client/model/InlineObject1.scala
@@ -0,0 +1,24 @@
+/**
+ * OpenAPI Petstore
+ * This is a sample server Petstore server. For this sample, you can use the api key `special-key` to test the authorization filters.
+ *
+ * The version of the OpenAPI document: 1.0.0
+ *
+ *
+ * NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech).
+ * https://openapi-generator.tech
+ * Do not edit the class manually.
+ */
+package org.openapitools.client.model
+
+import java.io.File
+import org.openapitools.client.core.ApiModel
+
+case class InlineObject1(
+ /* Additional data to pass to server */
+ additionalMetadata: Option[String] = None,
+ /* file to upload */
+ file: Option[File] = None
+) extends ApiModel
+
+
diff --git a/samples/client/petstore/scala-sttp/src/main/scala/org/openapitools/client/model/Order.scala b/samples/client/petstore/scala-sttp/src/main/scala/org/openapitools/client/model/Order.scala
new file mode 100644
index 00000000000..b8f11b0b3c3
--- /dev/null
+++ b/samples/client/petstore/scala-sttp/src/main/scala/org/openapitools/client/model/Order.scala
@@ -0,0 +1,41 @@
+/**
+ * OpenAPI Petstore
+ * This is a sample server Petstore server. For this sample, you can use the api key `special-key` to test the authorization filters.
+ *
+ * The version of the OpenAPI document: 1.0.0
+ *
+ *
+ * NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech).
+ * https://openapi-generator.tech
+ * Do not edit the class manually.
+ */
+package org.openapitools.client.model
+
+import org.joda.time.DateTime
+import org.openapitools.client.core.ApiModel
+
+ /**
+ * Pet Order
+ * An order for a pets from the pet store
+ */
+case class Order(
+ id: Option[Long] = None,
+ petId: Option[Long] = None,
+ quantity: Option[Int] = None,
+ shipDate: Option[DateTime] = None,
+ /* Order Status */
+ status: Option[OrderEnums.Status] = None,
+ complete: Option[Boolean] = None
+) extends ApiModel
+
+object OrderEnums {
+
+ type Status = Status.Value
+ object Status extends Enumeration {
+ val Placed = Value("placed")
+ val Approved = Value("approved")
+ val Delivered = Value("delivered")
+ }
+
+}
+
diff --git a/samples/client/petstore/scala-sttp/src/main/scala/org/openapitools/client/model/Pet.scala b/samples/client/petstore/scala-sttp/src/main/scala/org/openapitools/client/model/Pet.scala
new file mode 100644
index 00000000000..75b528c3c0a
--- /dev/null
+++ b/samples/client/petstore/scala-sttp/src/main/scala/org/openapitools/client/model/Pet.scala
@@ -0,0 +1,40 @@
+/**
+ * OpenAPI Petstore
+ * This is a sample server Petstore server. For this sample, you can use the api key `special-key` to test the authorization filters.
+ *
+ * The version of the OpenAPI document: 1.0.0
+ *
+ *
+ * NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech).
+ * https://openapi-generator.tech
+ * Do not edit the class manually.
+ */
+package org.openapitools.client.model
+
+import org.openapitools.client.core.ApiModel
+
+ /**
+ * a Pet
+ * A pet for sale in the pet store
+ */
+case class Pet(
+ id: Option[Long] = None,
+ category: Option[Category] = None,
+ name: String,
+ photoUrls: Seq[String],
+ tags: Option[Seq[Tag]] = None,
+ /* pet status in the store */
+ status: Option[PetEnums.Status] = None
+) extends ApiModel
+
+object PetEnums {
+
+ type Status = Status.Value
+ object Status extends Enumeration {
+ val Available = Value("available")
+ val Pending = Value("pending")
+ val Sold = Value("sold")
+ }
+
+}
+
diff --git a/samples/client/petstore/scala-sttp/src/main/scala/org/openapitools/client/model/Tag.scala b/samples/client/petstore/scala-sttp/src/main/scala/org/openapitools/client/model/Tag.scala
new file mode 100644
index 00000000000..299ee5161a8
--- /dev/null
+++ b/samples/client/petstore/scala-sttp/src/main/scala/org/openapitools/client/model/Tag.scala
@@ -0,0 +1,25 @@
+/**
+ * OpenAPI Petstore
+ * This is a sample server Petstore server. For this sample, you can use the api key `special-key` to test the authorization filters.
+ *
+ * The version of the OpenAPI document: 1.0.0
+ *
+ *
+ * NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech).
+ * https://openapi-generator.tech
+ * Do not edit the class manually.
+ */
+package org.openapitools.client.model
+
+import org.openapitools.client.core.ApiModel
+
+ /**
+ * Pet Tag
+ * A tag for a pet
+ */
+case class Tag(
+ id: Option[Long] = None,
+ name: Option[String] = None
+) extends ApiModel
+
+
diff --git a/samples/client/petstore/scala-sttp/src/main/scala/org/openapitools/client/model/User.scala b/samples/client/petstore/scala-sttp/src/main/scala/org/openapitools/client/model/User.scala
new file mode 100644
index 00000000000..bd2e6c3ba2a
--- /dev/null
+++ b/samples/client/petstore/scala-sttp/src/main/scala/org/openapitools/client/model/User.scala
@@ -0,0 +1,32 @@
+/**
+ * OpenAPI Petstore
+ * This is a sample server Petstore server. For this sample, you can use the api key `special-key` to test the authorization filters.
+ *
+ * The version of the OpenAPI document: 1.0.0
+ *
+ *
+ * NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech).
+ * https://openapi-generator.tech
+ * Do not edit the class manually.
+ */
+package org.openapitools.client.model
+
+import org.openapitools.client.core.ApiModel
+
+ /**
+ * a User
+ * A User who is purchasing from the pet store
+ */
+case class User(
+ id: Option[Long] = None,
+ username: Option[String] = None,
+ firstName: Option[String] = None,
+ lastName: Option[String] = None,
+ email: Option[String] = None,
+ password: Option[String] = None,
+ phone: Option[String] = None,
+ /* User Status */
+ userStatus: Option[Int] = None
+) extends ApiModel
+
+
diff --git a/samples/client/petstore/scala-sttp/src/test/scala/PetApiTest.scala b/samples/client/petstore/scala-sttp/src/test/scala/PetApiTest.scala
new file mode 100644
index 00000000000..f03ae223b51
--- /dev/null
+++ b/samples/client/petstore/scala-sttp/src/test/scala/PetApiTest.scala
@@ -0,0 +1,99 @@
+import org.junit.runner.RunWith
+import org.openapitools.client.api._
+import org.openapitools.client.core.{ApiInvoker, ApiKeyValue, SttpSerializer}
+import org.openapitools.client.model._
+import org.scalatest.Inspectors._
+import org.scalatest._
+import org.scalatest.junit.JUnitRunner
+import sttp.client.{HttpURLConnectionBackend, Identity, NothingT, SttpBackend}
+
+@RunWith(classOf[JUnitRunner])
+class PetApiTest extends AsyncFlatSpec with Matchers {
+
+ implicit val sttpSerializer: SttpSerializer = new SttpSerializer
+ implicit val backend: SttpBackend[Identity, Nothing, NothingT] = HttpURLConnectionBackend()
+ val api = new PetApi("https://petstore3.swagger.io/api/v3")
+
+ implicit val apiKey: ApiKeyValue = ApiKeyValue("api-key")
+
+ import ApiInvoker._
+
+ behavior of "PetApi"
+
+ it should "add and fetch a pet" in {
+ val petId = 1000
+ val createdPet = Pet(
+ Some(petId),
+ Some(Category(Some(1), Some("sold"))),
+ "dragon",
+ (for (i <- 1 to 10) yield "http://foo.com/photo/" + i).toList,
+ Some((for (i <- 1 to 5) yield org.openapitools.client.model.Tag(Some(i), Some("tag-" + i))).toList),
+ Some(PetEnums.Status.Sold)
+ )
+
+ val addPetRequest = api.addPet(createdPet)
+ val getPetRequest = api.getPetById(petId)
+
+ addPetRequest.result
+ val pet = getPetRequest.result
+
+ pet should have(
+ 'id(createdPet.id),
+ 'status(createdPet.status),
+ 'category(createdPet.category),
+ 'name(createdPet.name)
+ )
+ pet.tags should not be empty
+ pet.tags.get should contain theSameElementsInOrderAs createdPet.tags.get
+ pet.photoUrls should contain theSameElementsInOrderAs createdPet.photoUrls
+ }
+
+ it should "update a pet" in {
+ val petId = (Math.random() * 1000000000).toLong
+ val createdPetObj = Pet(
+ Some(petId),
+ Some(Category(Some(1), Some("sold"))),
+ "programmer",
+ (for (i <- 1 to 10) yield "http://foo.com/photo/" + i).toList,
+ Some((for (i <- 1 to 5) yield org.openapitools.client.model.Tag(Some(i), Some("tag-" + i))).toList),
+ Some(PetEnums.Status.Available)
+ )
+
+ val createdPet = api.addPet(createdPetObj).result
+ val pet = api.getPetById(createdPet.id.get).result
+ val updatedPetObj = pet.copy(status = Some(PetEnums.Status.Sold), name = "developer")
+ val updatedPet = api.updatePet(updatedPetObj).result
+ val updatedRequested = api.getPetById(createdPet.id.get).result
+
+ pet.name should be("programmer")
+ pet.status should be(Some(PetEnums.Status.Available))
+
+ updatedPet.name should be("developer")
+ updatedPet.status should be(Some(PetEnums.Status.Sold))
+
+ updatedRequested.name should be("developer")
+ updatedRequested.status should be(Some(PetEnums.Status.Sold))
+
+ }
+
+ it should "find pets by status" in {
+ val pets = api.findPetsByStatus(List("available")).result
+ pets should not be empty
+
+
+ forAll(pets.toList) { pet =>
+ pet.status should contain(PetEnums.Status.Available)
+ }
+ }
+
+ it should "find pets by tag" in {
+ val pets = api.findPetsByTags(List("tag1", "tag2")).result
+ pets should not be empty
+
+ forAll(pets.toList) { pet =>
+ val tagNames = pet.tags.toList.flatten.map(_.name).collect { case Some(name) => name }
+ tagNames should contain atLeastOneOf("tag1", "tag2")
+ }
+ }
+
+}
\ No newline at end of file