From a09822e169ea0be1d1a9658141cf6bed84137ed6 Mon Sep 17 00:00:00 2001
From: ghostbuster91 <kghost0@gmail.com>
Date: Thu, 4 Jun 2020 12:52:20 +0200
Subject: [PATCH 01/38] Base changes - remove apiModel - do not preinline
 response type - define sbt version - replace ApiRequestT with Request -
 update sttp version

---
 .../languages/ScalaSttpClientCodegen.java     |   1 +
 .../main/resources/scala-sttp/api.mustache    |   4 +-
 .../resources/scala-sttp/apiInvoker.mustache  |  28 -----
 .../resources/scala-sttp/build.sbt.mustache   |   8 +-
 .../main/resources/scala-sttp/model.mustache  |   3 +-
 .../project/build.properties.mustache         |   1 +
 .../resources/scala-sttp/requests.mustache    |  12 --
 .../scala-sttp/.openapi-generator/FILES       |   1 +
 samples/client/petstore/scala-sttp/build.sbt  |   8 +-
 .../scala-sttp/project/build.properties       |   1 +
 .../org/openapitools/client/api/PetApi.scala  |  18 ++-
 .../openapitools/client/api/StoreApi.scala    | 105 ++++++++++--------
 .../org/openapitools/client/api/UserApi.scala |  18 ++-
 .../openapitools/client/core/ApiInvoker.scala |  28 -----
 .../openapitools/client/core/requests.scala   |  12 --
 .../client/model/ApiResponse.scala            |   3 +-
 .../openapitools/client/model/Category.scala  |   3 +-
 .../client/model/InlineObject.scala           |   3 +-
 .../client/model/InlineObject1.scala          |   3 +-
 .../org/openapitools/client/model/Order.scala |   3 +-
 .../org/openapitools/client/model/Pet.scala   |   3 +-
 .../org/openapitools/client/model/Tag.scala   |   3 +-
 .../org/openapitools/client/model/User.scala  |   3 +-
 23 files changed, 94 insertions(+), 178 deletions(-)
 create mode 100644 modules/openapi-generator/src/main/resources/scala-sttp/project/build.properties.mustache
 create mode 100644 samples/client/petstore/scala-sttp/project/build.properties

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
index 43b48cb3114..bbda45b12ab 100644
--- 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
@@ -57,6 +57,7 @@ public class ScalaSttpClientCodegen extends ScalaAkkaClientCodegen implements Co
         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"));
+        supportingFiles.add(new SupportingFile("project/build.properties.mustache", "project", "build.properties"));
         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"));
diff --git a/modules/openapi-generator/src/main/resources/scala-sttp/api.mustache b/modules/openapi-generator/src/main/resources/scala-sttp/api.mustache
index 196a51a96f0..e0ba947f5d1 100644
--- a/modules/openapi-generator/src/main/resources/scala-sttp/api.mustache
+++ b/modules/openapi-generator/src/main/resources/scala-sttp/api.mustache
@@ -5,7 +5,6 @@ package {{package}}
 import {{import}}
 {{/imports}}
 import {{invokerPackage}}._
-import alias._
 import sttp.client._
 import sttp.model.Method
 
@@ -17,14 +16,13 @@ object {{classname}} {
 
 class {{classname}}(baseUrl: String)(implicit serializer: SttpSerializer) {
 
-  import Helpers._
   import serializer._
 
 {{#operation}}
 {{#javadocRenderer}}
 {{>javadoc}}
 {{/javadocRenderer}}
-  def {{operationId}}({{>methodParameters}}): ApiRequestT[{{>operationReturnType}}] =
+  def {{operationId}}({{>methodParameters}}): Request[Either[ResponseError[Exception],{{>operationReturnType}}], Nothing] =
     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}}
diff --git a/modules/openapi-generator/src/main/resources/scala-sttp/apiInvoker.mustache b/modules/openapi-generator/src/main/resources/scala-sttp/apiInvoker.mustache
index af26ef8f2bb..a6947991634 100644
--- a/modules/openapi-generator/src/main/resources/scala-sttp/apiInvoker.mustache
+++ b/modules/openapi-generator/src/main/resources/scala-sttp/apiInvoker.mustache
@@ -3,15 +3,12 @@ package {{invokerPackage}}
 
 import org.json4s._
 import sttp.client._
-import sttp.model.StatusCode
 import {{{apiPackage}}}.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 {
 
@@ -23,28 +20,3 @@ object Helpers {
   }
 
 }
-
-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/build.sbt.mustache b/modules/openapi-generator/src/main/resources/scala-sttp/build.sbt.mustache
index 00fe48b731d..f20a44d2ea9 100644
--- a/modules/openapi-generator/src/main/resources/scala-sttp/build.sbt.mustache
+++ b/modules/openapi-generator/src/main/resources/scala-sttp/build.sbt.mustache
@@ -2,13 +2,13 @@ version := "{{artifactVersion}}"
 name := "{{artifactId}}"
 organization := "{{groupId}}"
 
-scalaVersion := "2.13.0"
+scalaVersion := "2.13.2"
 
 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",
+  "com.softwaremill.sttp.client" %% "core" % "2.1.5",
+  "com.softwaremill.sttp.client" %% "json4s" % "2.1.5",
 {{#joda}}
   "joda-time" % "joda-time" % "2.10.1",
 {{/joda}}
@@ -24,4 +24,4 @@ scalacOptions := Seq(
   "-feature"
 )
 
-publishArtifact in (Compile, packageDoc) := false
\ No newline at end of file
+publishArtifact in (Compile, packageDoc) := false
diff --git a/modules/openapi-generator/src/main/resources/scala-sttp/model.mustache b/modules/openapi-generator/src/main/resources/scala-sttp/model.mustache
index 1f4da5283e3..f2cf2796234 100644
--- a/modules/openapi-generator/src/main/resources/scala-sttp/model.mustache
+++ b/modules/openapi-generator/src/main/resources/scala-sttp/model.mustache
@@ -4,7 +4,6 @@ package {{package}}
 {{#imports}}
 import {{import}}
 {{/imports}}
-import {{invokerPackage}}.ApiModel
 
 {{#models}}
 {{#model}}
@@ -23,7 +22,7 @@ case class {{classname}}(
   {{/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 {
diff --git a/modules/openapi-generator/src/main/resources/scala-sttp/project/build.properties.mustache b/modules/openapi-generator/src/main/resources/scala-sttp/project/build.properties.mustache
new file mode 100644
index 00000000000..6d441921c88
--- /dev/null
+++ b/modules/openapi-generator/src/main/resources/scala-sttp/project/build.properties.mustache
@@ -0,0 +1 @@
+sbt.version=1.2.4
diff --git a/modules/openapi-generator/src/main/resources/scala-sttp/requests.mustache b/modules/openapi-generator/src/main/resources/scala-sttp/requests.mustache
index a39706e43f4..7e6e1212029 100644
--- a/modules/openapi-generator/src/main/resources/scala-sttp/requests.mustache
+++ b/modules/openapi-generator/src/main/resources/scala-sttp/requests.mustache
@@ -3,18 +3,6 @@ package {{invokerPackage}}
 
 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
  */
diff --git a/samples/client/petstore/scala-sttp/.openapi-generator/FILES b/samples/client/petstore/scala-sttp/.openapi-generator/FILES
index ffe27d28081..ca35c1f7197 100644
--- a/samples/client/petstore/scala-sttp/.openapi-generator/FILES
+++ b/samples/client/petstore/scala-sttp/.openapi-generator/FILES
@@ -1,5 +1,6 @@
 README.md
 build.sbt
+project/build.properties
 src/main/scala/org/openapitools/client/api/EnumsSerializers.scala
 src/main/scala/org/openapitools/client/api/PetApi.scala
 src/main/scala/org/openapitools/client/api/StoreApi.scala
diff --git a/samples/client/petstore/scala-sttp/build.sbt b/samples/client/petstore/scala-sttp/build.sbt
index b940c8b6737..91a042edafb 100644
--- a/samples/client/petstore/scala-sttp/build.sbt
+++ b/samples/client/petstore/scala-sttp/build.sbt
@@ -2,13 +2,13 @@ version := "1.0.0"
 name := "scala-sttp-petstore"
 organization := "org.openapitools"
 
-scalaVersion := "2.13.0"
+scalaVersion := "2.13.2"
 
 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",
+  "com.softwaremill.sttp.client" %% "core" % "2.1.5",
+  "com.softwaremill.sttp.client" %% "json4s" % "2.1.5",
   "org.json4s" %% "json4s-jackson" % "3.6.7",
   // test dependencies
   "org.scalatest" %% "scalatest" % "3.0.8" % Test,
@@ -21,4 +21,4 @@ scalacOptions := Seq(
   "-feature"
 )
 
-publishArtifact in (Compile, packageDoc) := false
\ No newline at end of file
+publishArtifact in (Compile, packageDoc) := false
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..6d441921c88
--- /dev/null
+++ b/samples/client/petstore/scala-sttp/project/build.properties
@@ -0,0 +1 @@
+sbt.version=1.2.4
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
index 5211d09c9c5..6bc2a5418ab 100644
--- 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
@@ -15,7 +15,6 @@ 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
 
@@ -26,7 +25,6 @@ object PetApi {
 
 class PetApi(baseUrl: String)(implicit serializer: SttpSerializer) {
 
-  import Helpers._
   import serializer._
 
   /**
@@ -36,7 +34,7 @@ class PetApi(baseUrl: String)(implicit serializer: SttpSerializer) {
    * 
    * @param pet Pet object that needs to be added to the store
    */
-  def addPet(pet: Pet): ApiRequestT[Pet] =
+  def addPet(pet: Pet): Request[Either[ResponseError[Exception],Pet], Nothing] =
     basicRequest
       .method(Method.POST, uri"$baseUrl/pet")
       .contentType("application/json")
@@ -50,7 +48,7 @@ class PetApi(baseUrl: String)(implicit serializer: SttpSerializer) {
    * @param petId Pet id to delete
    * @param apiKey 
    */
-  def deletePet(petId: Long, apiKey: Option[String] = None): ApiRequestT[Unit] =
+  def deletePet(petId: Long, apiKey: Option[String] = None): Request[Either[ResponseError[Exception],Unit], Nothing] =
     basicRequest
       .method(Method.DELETE, uri"$baseUrl/pet/${petId}")
       .contentType("application/json")
@@ -66,7 +64,7 @@ class PetApi(baseUrl: String)(implicit serializer: SttpSerializer) {
    * 
    * @param status Status values that need to be considered for filter
    */
-  def findPetsByStatus(status: Seq[String]): ApiRequestT[Seq[Pet]] =
+  def findPetsByStatus(status: Seq[String]): Request[Either[ResponseError[Exception],Seq[Pet]], Nothing] =
     basicRequest
       .method(Method.GET, uri"$baseUrl/pet/findByStatus?status=$status")
       .contentType("application/json")
@@ -81,7 +79,7 @@ class PetApi(baseUrl: String)(implicit serializer: SttpSerializer) {
    * 
    * @param tags Tags to filter by
    */
-  def findPetsByTags(tags: Seq[String]): ApiRequestT[Seq[Pet]] =
+  def findPetsByTags(tags: Seq[String]): Request[Either[ResponseError[Exception],Seq[Pet]], Nothing] =
     basicRequest
       .method(Method.GET, uri"$baseUrl/pet/findByTags?tags=$tags")
       .contentType("application/json")
@@ -100,7 +98,7 @@ class PetApi(baseUrl: String)(implicit serializer: SttpSerializer) {
    * 
    * @param petId ID of pet to return
    */
-  def getPetById(petId: Long)(implicit apiKey: ApiKeyValue): ApiRequestT[Pet] =
+  def getPetById(petId: Long)(implicit apiKey: ApiKeyValue): Request[Either[ResponseError[Exception],Pet], Nothing] =
     basicRequest
       .method(Method.GET, uri"$baseUrl/pet/${petId}")
       .contentType("application/json")
@@ -116,7 +114,7 @@ class PetApi(baseUrl: String)(implicit serializer: SttpSerializer) {
    * 
    * @param pet Pet object that needs to be added to the store
    */
-  def updatePet(pet: Pet): ApiRequestT[Pet] =
+  def updatePet(pet: Pet): Request[Either[ResponseError[Exception],Pet], Nothing] =
     basicRequest
       .method(Method.PUT, uri"$baseUrl/pet")
       .contentType("application/json")
@@ -131,7 +129,7 @@ class PetApi(baseUrl: String)(implicit serializer: SttpSerializer) {
    * @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] =
+  def updatePetWithForm(petId: Long, name: Option[String] = None, status: Option[String] = None): Request[Either[ResponseError[Exception],Unit], Nothing] =
     basicRequest
       .method(Method.POST, uri"$baseUrl/pet/${petId}")
       .contentType("application/x-www-form-urlencoded")
@@ -149,7 +147,7 @@ class PetApi(baseUrl: String)(implicit serializer: SttpSerializer) {
    * @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] =
+  def uploadFile(petId: Long, additionalMetadata: Option[String] = None, file: Option[File] = None): Request[Either[ResponseError[Exception],ApiResponse], Nothing] =
     basicRequest
       .method(Method.POST, uri"$baseUrl/pet/${petId}/uploadImage")
       .contentType("multipart/form-data")
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
index 907cc9f42f0..b4518c2863d 100644
--- 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
@@ -1,57 +1,61 @@
 /**
- * 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.
- */
+  * 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)
+  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] =
+    * 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
+  ): Request[Either[ResponseError[Exception], Unit], Nothing] =
     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]] =
+    * 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
+  ): Request[Either[ResponseError[Exception], Map[String, Int]], Nothing] =
     basicRequest
       .method(Method.GET, uri"$baseUrl/store/inventory")
       .contentType("application/json")
@@ -59,29 +63,33 @@ class StoreApi(baseUrl: String)(implicit serializer: SttpSerializer) {
       .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] =
+    * 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
+  ): Request[Either[ResponseError[Exception], Order], Nothing] =
     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] =
+    * Expected answers:
+    *   code 200 : Order (successful operation)
+    *   code 400 :  (Invalid Order)
+    *
+    * @param order order placed for purchasing the pet
+    */
+  def placeOrder(
+    order: Order
+  ): Request[Either[ResponseError[Exception], Order], Nothing] =
     basicRequest
       .method(Method.POST, uri"$baseUrl/store/order")
       .contentType("application/json")
@@ -89,4 +97,3 @@ class StoreApi(baseUrl: String)(implicit serializer: SttpSerializer) {
       .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
index 34679dea5d7..cc096610559 100644
--- 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
@@ -13,7 +13,6 @@ 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
 
@@ -24,7 +23,6 @@ object UserApi {
 
 class UserApi(baseUrl: String)(implicit serializer: SttpSerializer) {
 
-  import Helpers._
   import serializer._
 
   /**
@@ -38,7 +36,7 @@ class UserApi(baseUrl: String)(implicit serializer: SttpSerializer) {
    * 
    * @param user Created user object
    */
-  def createUser(user: User)(implicit apiKey: ApiKeyValue): ApiRequestT[Unit] =
+  def createUser(user: User)(implicit apiKey: ApiKeyValue): Request[Either[ResponseError[Exception],Unit], Nothing] =
     basicRequest
       .method(Method.POST, uri"$baseUrl/user")
       .contentType("application/json")
@@ -55,7 +53,7 @@ class UserApi(baseUrl: String)(implicit serializer: SttpSerializer) {
    * 
    * @param user List of user object
    */
-  def createUsersWithArrayInput(user: Seq[User])(implicit apiKey: ApiKeyValue): ApiRequestT[Unit] =
+  def createUsersWithArrayInput(user: Seq[User])(implicit apiKey: ApiKeyValue): Request[Either[ResponseError[Exception],Unit], Nothing] =
     basicRequest
       .method(Method.POST, uri"$baseUrl/user/createWithArray")
       .contentType("application/json")
@@ -72,7 +70,7 @@ class UserApi(baseUrl: String)(implicit serializer: SttpSerializer) {
    * 
    * @param user List of user object
    */
-  def createUsersWithListInput(user: Seq[User])(implicit apiKey: ApiKeyValue): ApiRequestT[Unit] =
+  def createUsersWithListInput(user: Seq[User])(implicit apiKey: ApiKeyValue): Request[Either[ResponseError[Exception],Unit], Nothing] =
     basicRequest
       .method(Method.POST, uri"$baseUrl/user/createWithList")
       .contentType("application/json")
@@ -92,7 +90,7 @@ class UserApi(baseUrl: String)(implicit serializer: SttpSerializer) {
    * 
    * @param username The name that needs to be deleted
    */
-  def deleteUser(username: String)(implicit apiKey: ApiKeyValue): ApiRequestT[Unit] =
+  def deleteUser(username: String)(implicit apiKey: ApiKeyValue): Request[Either[ResponseError[Exception],Unit], Nothing] =
     basicRequest
       .method(Method.DELETE, uri"$baseUrl/user/${username}")
       .contentType("application/json")
@@ -107,7 +105,7 @@ class UserApi(baseUrl: String)(implicit serializer: SttpSerializer) {
    * 
    * @param username The name that needs to be fetched. Use user1 for testing.
    */
-  def getUserByName(username: String): ApiRequestT[User] =
+  def getUserByName(username: String): Request[Either[ResponseError[Exception],User], Nothing] =
     basicRequest
       .method(Method.GET, uri"$baseUrl/user/${username}")
       .contentType("application/json")
@@ -125,7 +123,7 @@ class UserApi(baseUrl: String)(implicit serializer: SttpSerializer) {
    * @param username The user name for login
    * @param password The password for login in clear text
    */
-  def loginUser(username: String, password: String): ApiRequestT[String] =
+  def loginUser(username: String, password: String): Request[Either[ResponseError[Exception],String], Nothing] =
     basicRequest
       .method(Method.GET, uri"$baseUrl/user/login?username=$username&password=$password")
       .contentType("application/json")
@@ -138,7 +136,7 @@ class UserApi(baseUrl: String)(implicit serializer: SttpSerializer) {
    * Available security schemes:
    *   api_key (apiKey)
    */
-  def logoutUser()(implicit apiKey: ApiKeyValue): ApiRequestT[Unit] =
+  def logoutUser()(implicit apiKey: ApiKeyValue): Request[Either[ResponseError[Exception],Unit], Nothing] =
     basicRequest
       .method(Method.GET, uri"$baseUrl/user/logout")
       .contentType("application/json")
@@ -158,7 +156,7 @@ class UserApi(baseUrl: String)(implicit serializer: SttpSerializer) {
    * @param username name that need to be deleted
    * @param user Updated user object
    */
-  def updateUser(username: String, user: User)(implicit apiKey: ApiKeyValue): ApiRequestT[Unit] =
+  def updateUser(username: String, user: User)(implicit apiKey: ApiKeyValue): Request[Either[ResponseError[Exception],Unit], Nothing] =
     basicRequest
       .method(Method.PUT, uri"$baseUrl/user/${username}")
       .contentType("application/json")
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
index dc98ff4d136..fb99518cd4e 100644
--- 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
@@ -13,15 +13,12 @@ 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 {
 
@@ -33,28 +30,3 @@ object Helpers {
   }
 
 }
-
-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/requests.scala b/samples/client/petstore/scala-sttp/src/main/scala/org/openapitools/client/core/requests.scala
index 1f45be8103e..e1d4f3915cc 100644
--- 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
@@ -13,18 +13,6 @@ 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
  */
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
index 3a3b6d6f499..aaaeae4c340 100644
--- 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
@@ -11,7 +11,6 @@
  */
 package org.openapitools.client.model
 
-import org.openapitools.client.core.ApiModel
 
   /**
    * An uploaded response
@@ -21,6 +20,6 @@ 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
index 011164617cf..81d132f226e 100644
--- 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
@@ -11,7 +11,6 @@
  */
 package org.openapitools.client.model
 
-import org.openapitools.client.core.ApiModel
 
   /**
    * Pet category
@@ -20,6 +19,6 @@ import org.openapitools.client.core.ApiModel
 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
index a8c5493161a..bf97d86b279 100644
--- 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
@@ -11,13 +11,12 @@
  */
 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
index 480cf8c2e10..73014a0bfde 100644
--- 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
@@ -12,13 +12,12 @@
 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
index baa0c0cb14a..222b0564f54 100644
--- 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
@@ -12,7 +12,6 @@
 package org.openapitools.client.model
 
 import java.time.OffsetDateTime
-import org.openapitools.client.core.ApiModel
 
   /**
    * Pet Order
@@ -26,7 +25,7 @@ case class Order(
   /* Order Status */
   status: Option[OrderEnums.Status] = None,
   complete: Option[Boolean] = None
-) extends ApiModel
+)
 
 object OrderEnums {
 
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
index 75b528c3c0a..0e48ba900d8 100644
--- 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
@@ -11,7 +11,6 @@
  */
 package org.openapitools.client.model
 
-import org.openapitools.client.core.ApiModel
 
   /**
    * a Pet
@@ -25,7 +24,7 @@ case class Pet(
   tags: Option[Seq[Tag]] = None,
   /* pet status in the store */
   status: Option[PetEnums.Status] = None
-) extends ApiModel
+)
 
 object PetEnums {
 
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
index 299ee5161a8..d1ce00a9a84 100644
--- 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
@@ -11,7 +11,6 @@
  */
 package org.openapitools.client.model
 
-import org.openapitools.client.core.ApiModel
 
   /**
    * Pet Tag
@@ -20,6 +19,6 @@ import org.openapitools.client.core.ApiModel
 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
index bd2e6c3ba2a..729b4bcc658 100644
--- 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
@@ -11,7 +11,6 @@
  */
 package org.openapitools.client.model
 
-import org.openapitools.client.core.ApiModel
 
   /**
    * a User
@@ -27,6 +26,6 @@ case class User(
   phone: Option[String] = None,
   /* User Status */
   userStatus: Option[Int] = None
-) extends ApiModel
+)
 
 
-- 
GitLab


From a4124448cab670d23a573f5d49e38dbc1d55a667 Mon Sep 17 00:00:00 2001
From: ghostbuster91 <kghost0@gmail.com>
Date: Thu, 4 Jun 2020 13:00:26 +0200
Subject: [PATCH 02/38] Fix rendering too many colons

---
 .../main/resources/scala-sttp/api.mustache    |   2 +-
 .../org/openapitools/client/api/PetApi.scala  | 197 ++++++++++--------
 .../openapitools/client/api/StoreApi.scala    | 103 +++++----
 3 files changed, 154 insertions(+), 148 deletions(-)

diff --git a/modules/openapi-generator/src/main/resources/scala-sttp/api.mustache b/modules/openapi-generator/src/main/resources/scala-sttp/api.mustache
index e0ba947f5d1..3d3ee4e0165 100644
--- a/modules/openapi-generator/src/main/resources/scala-sttp/api.mustache
+++ b/modules/openapi-generator/src/main/resources/scala-sttp/api.mustache
@@ -32,7 +32,7 @@ class {{classname}}(baseUrl: String)(implicit serializer: SttpSerializer) {
       .header("{{keyParamName}}", apiKey.value){{/isKeyInHeader}}{{#isKeyInCookie}}
       .cookie("{{keyParamName}}", apiKey.value){{/isKeyInCookie}}{{/isApiKey}}{{/authMethods}}{{#formParams.0}}
       .body(Map({{#formParams}}
-        {{>paramFormCreation}},{{/formParams}}
+        {{>paramFormCreation}}{{#hasMore}}, {{/hasMore}}{{/formParams}}
       )){{/formParams.0}}{{#bodyParam}}
       .body({{paramName}}){{/bodyParam}}
       .response(asJson[{{>operationReturnType}}])
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
index 6bc2a5418ab..38be9c82192 100644
--- 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
@@ -1,14 +1,14 @@
 /**
- * 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.
- */
+  * 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
@@ -20,7 +20,9 @@ import sttp.model.Method
 
 object PetApi {
 
-  def apply(baseUrl: String = "http://petstore.swagger.io/v2")(implicit serializer: SttpSerializer) = new PetApi(baseUrl)
+  def apply(baseUrl: String = "http://petstore.swagger.io/v2")(
+    implicit serializer: SttpSerializer
+  ) = new PetApi(baseUrl)
 }
 
 class PetApi(baseUrl: String)(implicit serializer: SttpSerializer) {
@@ -28,13 +30,15 @@ class PetApi(baseUrl: String)(implicit serializer: SttpSerializer) {
   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): Request[Either[ResponseError[Exception],Pet], Nothing] =
+    * 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
+  ): Request[Either[ResponseError[Exception], Pet], Nothing] =
     basicRequest
       .method(Method.POST, uri"$baseUrl/pet")
       .contentType("application/json")
@@ -42,63 +46,71 @@ class PetApi(baseUrl: String)(implicit serializer: SttpSerializer) {
       .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): Request[Either[ResponseError[Exception],Unit], Nothing] =
+    * Expected answers:
+    *   code 400 :  (Invalid pet value)
+    *
+    * @param petId Pet id to delete
+    * @param apiKey
+    */
+  def deletePet(
+    petId: Long,
+    apiKey: Option[String] = None
+  ): Request[Either[ResponseError[Exception], Unit], Nothing] =
     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]): Request[Either[ResponseError[Exception],Seq[Pet]], Nothing] =
+    * 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]
+  ): Request[Either[ResponseError[Exception], Seq[Pet]], Nothing] =
     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]): Request[Either[ResponseError[Exception],Seq[Pet]], Nothing] =
+    * 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]
+  ): Request[Either[ResponseError[Exception], Seq[Pet]], Nothing] =
     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): Request[Either[ResponseError[Exception],Pet], Nothing] =
+    * 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
+  ): Request[Either[ResponseError[Exception], Pet], Nothing] =
     basicRequest
       .method(Method.GET, uri"$baseUrl/pet/${petId}")
       .contentType("application/json")
@@ -106,15 +118,17 @@ class PetApi(baseUrl: String)(implicit serializer: SttpSerializer) {
       .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): Request[Either[ResponseError[Exception],Pet], Nothing] =
+    * 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
+  ): Request[Either[ResponseError[Exception], Pet], Nothing] =
     basicRequest
       .method(Method.PUT, uri"$baseUrl/pet")
       .contentType("application/json")
@@ -122,40 +136,41 @@ class PetApi(baseUrl: String)(implicit serializer: SttpSerializer) {
       .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): Request[Either[ResponseError[Exception],Unit], Nothing] =
+    * 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
+  ): Request[Either[ResponseError[Exception], Unit], Nothing] =
     basicRequest
       .method(Method.POST, uri"$baseUrl/pet/${petId}")
       .contentType("application/x-www-form-urlencoded")
-      .body(Map(
-        "name" -> name,
-        "status" -> status,
-      ))
+      .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): Request[Either[ResponseError[Exception],ApiResponse], Nothing] =
+    * 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
+  ): Request[Either[ResponseError[Exception], ApiResponse], Nothing] =
     basicRequest
       .method(Method.POST, uri"$baseUrl/pet/${petId}/uploadImage")
       .contentType("multipart/form-data")
-      .body(Map(
-        "additionalMetadata" -> additionalMetadata,
-        "file" -> file,
-      ))
+      .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
index b4518c2863d..bbd816a237b 100644
--- 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
@@ -1,14 +1,14 @@
 /**
-  * 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.
-  */
+ * 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
@@ -18,9 +18,7 @@ import sttp.model.Method
 
 object StoreApi {
 
-  def apply(baseUrl: String = "http://petstore.swagger.io/v2")(
-    implicit serializer: SttpSerializer
-  ) = new StoreApi(baseUrl)
+  def apply(baseUrl: String = "http://petstore.swagger.io/v2")(implicit serializer: SttpSerializer) = new StoreApi(baseUrl)
 }
 
 class StoreApi(baseUrl: String)(implicit serializer: SttpSerializer) {
@@ -28,34 +26,30 @@ class StoreApi(baseUrl: String)(implicit serializer: SttpSerializer) {
   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
-  ): Request[Either[ResponseError[Exception], Unit], Nothing] =
+   * 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): Request[Either[ResponseError[Exception],Unit], Nothing] =
     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
-  ): Request[Either[ResponseError[Exception], Map[String, Int]], Nothing] =
+   * 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): Request[Either[ResponseError[Exception],Map[String, Int]], Nothing] =
     basicRequest
       .method(Method.GET, uri"$baseUrl/store/inventory")
       .contentType("application/json")
@@ -63,33 +57,29 @@ class StoreApi(baseUrl: String)(implicit serializer: SttpSerializer) {
       .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
-  ): Request[Either[ResponseError[Exception], Order], Nothing] =
+   * 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): Request[Either[ResponseError[Exception],Order], Nothing] =
     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
-  ): Request[Either[ResponseError[Exception], Order], Nothing] =
+   * Expected answers:
+   *   code 200 : Order (successful operation)
+   *   code 400 :  (Invalid Order)
+   * 
+   * @param order order placed for purchasing the pet
+   */
+  def placeOrder(order: Order): Request[Either[ResponseError[Exception],Order], Nothing] =
     basicRequest
       .method(Method.POST, uri"$baseUrl/store/order")
       .contentType("application/json")
@@ -97,3 +87,4 @@ class StoreApi(baseUrl: String)(implicit serializer: SttpSerializer) {
       .response(asJson[Order])
 
 }
+
-- 
GitLab


From e8c3890ae141daab6a201b3d7e17aa39a9339516 Mon Sep 17 00:00:00 2001
From: ghostbuster91 <kghost0@gmail.com>
Date: Thu, 4 Jun 2020 13:11:27 +0200
Subject: [PATCH 03/38] Fix formatting

---
 .../main/resources/scala-sttp/api.mustache    |   2 +-
 .../org/openapitools/client/api/PetApi.scala  | 197 ++++++++----------
 .../openapitools/client/api/StoreApi.scala    |   8 +-
 .../org/openapitools/client/api/UserApi.scala |  16 +-
 4 files changed, 104 insertions(+), 119 deletions(-)

diff --git a/modules/openapi-generator/src/main/resources/scala-sttp/api.mustache b/modules/openapi-generator/src/main/resources/scala-sttp/api.mustache
index 3d3ee4e0165..23f75ae483c 100644
--- a/modules/openapi-generator/src/main/resources/scala-sttp/api.mustache
+++ b/modules/openapi-generator/src/main/resources/scala-sttp/api.mustache
@@ -22,7 +22,7 @@ class {{classname}}(baseUrl: String)(implicit serializer: SttpSerializer) {
 {{#javadocRenderer}}
 {{>javadoc}}
 {{/javadocRenderer}}
-  def {{operationId}}({{>methodParameters}}): Request[Either[ResponseError[Exception],{{>operationReturnType}}], Nothing] =
+  def {{operationId}}({{>methodParameters}}): Request[Either[ResponseError[Exception], {{>operationReturnType}}], Nothing] =
     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}}
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
index 38be9c82192..159b68ea86a 100644
--- 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
@@ -1,14 +1,14 @@
 /**
-  * 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.
-  */
+ * 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
@@ -20,9 +20,7 @@ import sttp.model.Method
 
 object PetApi {
 
-  def apply(baseUrl: String = "http://petstore.swagger.io/v2")(
-    implicit serializer: SttpSerializer
-  ) = new PetApi(baseUrl)
+  def apply(baseUrl: String = "http://petstore.swagger.io/v2")(implicit serializer: SttpSerializer) = new PetApi(baseUrl)
 }
 
 class PetApi(baseUrl: String)(implicit serializer: SttpSerializer) {
@@ -30,15 +28,13 @@ class PetApi(baseUrl: String)(implicit serializer: SttpSerializer) {
   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
-  ): Request[Either[ResponseError[Exception], Pet], Nothing] =
+   * 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): Request[Either[ResponseError[Exception], Pet], Nothing] =
     basicRequest
       .method(Method.POST, uri"$baseUrl/pet")
       .contentType("application/json")
@@ -46,71 +42,63 @@ class PetApi(baseUrl: String)(implicit serializer: SttpSerializer) {
       .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
-  ): Request[Either[ResponseError[Exception], Unit], Nothing] =
+   * Expected answers:
+   *   code 400 :  (Invalid pet value)
+   * 
+   * @param petId Pet id to delete
+   * @param apiKey 
+   */
+  def deletePet(petId: Long, apiKey: Option[String] = None): Request[Either[ResponseError[Exception], Unit], Nothing] =
     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]
-  ): Request[Either[ResponseError[Exception], Seq[Pet]], Nothing] =
+   * 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]): Request[Either[ResponseError[Exception], Seq[Pet]], Nothing] =
     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]
-  ): Request[Either[ResponseError[Exception], Seq[Pet]], Nothing] =
+   * 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]): Request[Either[ResponseError[Exception], Seq[Pet]], Nothing] =
     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
-  ): Request[Either[ResponseError[Exception], Pet], Nothing] =
+   * 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): Request[Either[ResponseError[Exception], Pet], Nothing] =
     basicRequest
       .method(Method.GET, uri"$baseUrl/pet/${petId}")
       .contentType("application/json")
@@ -118,17 +106,15 @@ class PetApi(baseUrl: String)(implicit serializer: SttpSerializer) {
       .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
-  ): Request[Either[ResponseError[Exception], Pet], Nothing] =
+   * 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): Request[Either[ResponseError[Exception], Pet], Nothing] =
     basicRequest
       .method(Method.PUT, uri"$baseUrl/pet")
       .contentType("application/json")
@@ -136,41 +122,40 @@ class PetApi(baseUrl: String)(implicit serializer: SttpSerializer) {
       .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
-  ): Request[Either[ResponseError[Exception], Unit], Nothing] =
+   * 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): Request[Either[ResponseError[Exception], Unit], Nothing] =
     basicRequest
       .method(Method.POST, uri"$baseUrl/pet/${petId}")
       .contentType("application/x-www-form-urlencoded")
-      .body(Map("name" -> name, "status" -> status))
+      .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
-  ): Request[Either[ResponseError[Exception], ApiResponse], Nothing] =
+   * 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): Request[Either[ResponseError[Exception], ApiResponse], Nothing] =
     basicRequest
       .method(Method.POST, uri"$baseUrl/pet/${petId}/uploadImage")
       .contentType("multipart/form-data")
-      .body(Map("additionalMetadata" -> additionalMetadata, "file" -> file))
+      .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
index bbd816a237b..2345bdf5508 100644
--- 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
@@ -34,7 +34,7 @@ class StoreApi(baseUrl: String)(implicit serializer: SttpSerializer) {
    * 
    * @param orderId ID of the order that needs to be deleted
    */
-  def deleteOrder(orderId: String): Request[Either[ResponseError[Exception],Unit], Nothing] =
+  def deleteOrder(orderId: String): Request[Either[ResponseError[Exception], Unit], Nothing] =
     basicRequest
       .method(Method.DELETE, uri"$baseUrl/store/order/${orderId}")
       .contentType("application/json")
@@ -49,7 +49,7 @@ class StoreApi(baseUrl: String)(implicit serializer: SttpSerializer) {
    * Available security schemes:
    *   api_key (apiKey)
    */
-  def getInventory()(implicit apiKey: ApiKeyValue): Request[Either[ResponseError[Exception],Map[String, Int]], Nothing] =
+  def getInventory()(implicit apiKey: ApiKeyValue): Request[Either[ResponseError[Exception], Map[String, Int]], Nothing] =
     basicRequest
       .method(Method.GET, uri"$baseUrl/store/inventory")
       .contentType("application/json")
@@ -66,7 +66,7 @@ class StoreApi(baseUrl: String)(implicit serializer: SttpSerializer) {
    * 
    * @param orderId ID of pet that needs to be fetched
    */
-  def getOrderById(orderId: Long): Request[Either[ResponseError[Exception],Order], Nothing] =
+  def getOrderById(orderId: Long): Request[Either[ResponseError[Exception], Order], Nothing] =
     basicRequest
       .method(Method.GET, uri"$baseUrl/store/order/${orderId}")
       .contentType("application/json")
@@ -79,7 +79,7 @@ class StoreApi(baseUrl: String)(implicit serializer: SttpSerializer) {
    * 
    * @param order order placed for purchasing the pet
    */
-  def placeOrder(order: Order): Request[Either[ResponseError[Exception],Order], Nothing] =
+  def placeOrder(order: Order): Request[Either[ResponseError[Exception], Order], Nothing] =
     basicRequest
       .method(Method.POST, uri"$baseUrl/store/order")
       .contentType("application/json")
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
index cc096610559..4a36ce95949 100644
--- 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
@@ -36,7 +36,7 @@ class UserApi(baseUrl: String)(implicit serializer: SttpSerializer) {
    * 
    * @param user Created user object
    */
-  def createUser(user: User)(implicit apiKey: ApiKeyValue): Request[Either[ResponseError[Exception],Unit], Nothing] =
+  def createUser(user: User)(implicit apiKey: ApiKeyValue): Request[Either[ResponseError[Exception], Unit], Nothing] =
     basicRequest
       .method(Method.POST, uri"$baseUrl/user")
       .contentType("application/json")
@@ -53,7 +53,7 @@ class UserApi(baseUrl: String)(implicit serializer: SttpSerializer) {
    * 
    * @param user List of user object
    */
-  def createUsersWithArrayInput(user: Seq[User])(implicit apiKey: ApiKeyValue): Request[Either[ResponseError[Exception],Unit], Nothing] =
+  def createUsersWithArrayInput(user: Seq[User])(implicit apiKey: ApiKeyValue): Request[Either[ResponseError[Exception], Unit], Nothing] =
     basicRequest
       .method(Method.POST, uri"$baseUrl/user/createWithArray")
       .contentType("application/json")
@@ -70,7 +70,7 @@ class UserApi(baseUrl: String)(implicit serializer: SttpSerializer) {
    * 
    * @param user List of user object
    */
-  def createUsersWithListInput(user: Seq[User])(implicit apiKey: ApiKeyValue): Request[Either[ResponseError[Exception],Unit], Nothing] =
+  def createUsersWithListInput(user: Seq[User])(implicit apiKey: ApiKeyValue): Request[Either[ResponseError[Exception], Unit], Nothing] =
     basicRequest
       .method(Method.POST, uri"$baseUrl/user/createWithList")
       .contentType("application/json")
@@ -90,7 +90,7 @@ class UserApi(baseUrl: String)(implicit serializer: SttpSerializer) {
    * 
    * @param username The name that needs to be deleted
    */
-  def deleteUser(username: String)(implicit apiKey: ApiKeyValue): Request[Either[ResponseError[Exception],Unit], Nothing] =
+  def deleteUser(username: String)(implicit apiKey: ApiKeyValue): Request[Either[ResponseError[Exception], Unit], Nothing] =
     basicRequest
       .method(Method.DELETE, uri"$baseUrl/user/${username}")
       .contentType("application/json")
@@ -105,7 +105,7 @@ class UserApi(baseUrl: String)(implicit serializer: SttpSerializer) {
    * 
    * @param username The name that needs to be fetched. Use user1 for testing.
    */
-  def getUserByName(username: String): Request[Either[ResponseError[Exception],User], Nothing] =
+  def getUserByName(username: String): Request[Either[ResponseError[Exception], User], Nothing] =
     basicRequest
       .method(Method.GET, uri"$baseUrl/user/${username}")
       .contentType("application/json")
@@ -123,7 +123,7 @@ class UserApi(baseUrl: String)(implicit serializer: SttpSerializer) {
    * @param username The user name for login
    * @param password The password for login in clear text
    */
-  def loginUser(username: String, password: String): Request[Either[ResponseError[Exception],String], Nothing] =
+  def loginUser(username: String, password: String): Request[Either[ResponseError[Exception], String], Nothing] =
     basicRequest
       .method(Method.GET, uri"$baseUrl/user/login?username=$username&password=$password")
       .contentType("application/json")
@@ -136,7 +136,7 @@ class UserApi(baseUrl: String)(implicit serializer: SttpSerializer) {
    * Available security schemes:
    *   api_key (apiKey)
    */
-  def logoutUser()(implicit apiKey: ApiKeyValue): Request[Either[ResponseError[Exception],Unit], Nothing] =
+  def logoutUser()(implicit apiKey: ApiKeyValue): Request[Either[ResponseError[Exception], Unit], Nothing] =
     basicRequest
       .method(Method.GET, uri"$baseUrl/user/logout")
       .contentType("application/json")
@@ -156,7 +156,7 @@ class UserApi(baseUrl: String)(implicit serializer: SttpSerializer) {
    * @param username name that need to be deleted
    * @param user Updated user object
    */
-  def updateUser(username: String, user: User)(implicit apiKey: ApiKeyValue): Request[Either[ResponseError[Exception],Unit], Nothing] =
+  def updateUser(username: String, user: User)(implicit apiKey: ApiKeyValue): Request[Either[ResponseError[Exception], Unit], Nothing] =
     basicRequest
       .method(Method.PUT, uri"$baseUrl/user/${username}")
       .contentType("application/json")
-- 
GitLab


From e3a065486b4bbe2dfefc0cf56cbf92d698d93603 Mon Sep 17 00:00:00 2001
From: ghostbuster91 <kghost0@gmail.com>
Date: Thu, 4 Jun 2020 14:41:58 +0200
Subject: [PATCH 04/38] Allow sttp version customization

---
 .../codegen/languages/ScalaSttpClientCodegen.java   | 10 ++++++++++
 .../main/resources/scala-sttp/build.sbt.mustache    |  9 +++------
 samples/client/petstore/scala-sttp/build.sbt        | 13 +++----------
 3 files changed, 16 insertions(+), 16 deletions(-)

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
index bbda45b12ab..e1cde845033 100644
--- 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
@@ -18,6 +18,7 @@ package org.openapitools.codegen.languages;
 
 import io.swagger.v3.oas.models.Operation;
 import io.swagger.v3.oas.models.servers.Server;
+import org.openapitools.codegen.CliOption;
 import org.openapitools.codegen.CodegenConfig;
 import org.openapitools.codegen.CodegenOperation;
 import org.openapitools.codegen.SupportingFile;
@@ -28,6 +29,10 @@ import java.io.File;
 import java.util.List;
 
 public class ScalaSttpClientCodegen extends ScalaAkkaClientCodegen implements CodegenConfig {
+    public static final String STTP_CLIENT_VERSION = "sttpClientVersion";
+    public static final String STTP_CLIENT_VERSION_DESC = "The version of stpp client";
+    public static final String STTP_CLIENT_VERSION_DEFAULT = "2.1.5";
+
     public ScalaSttpClientCodegen() {
         super();
         generatorMetadata = GeneratorMetadata.newBuilder(generatorMetadata)
@@ -36,6 +41,8 @@ public class ScalaSttpClientCodegen extends ScalaAkkaClientCodegen implements Co
 
         embeddedTemplateDir = templateDir = "scala-sttp";
         outputFolder = "generated-code/scala-sttp";
+
+        cliOptions.add(CliOption.newString(STTP_CLIENT_VERSION,STTP_CLIENT_VERSION_DESC).defaultValue(STTP_CLIENT_VERSION_DEFAULT));
     }
 
     @Override
@@ -50,6 +57,9 @@ public class ScalaSttpClientCodegen extends ScalaAkkaClientCodegen implements Co
             additionalProperties.put("apiPackage", apiPackage);
             additionalProperties.put("modelPackage", modelPackage);
         }
+        if(!additionalProperties.containsKey(STTP_CLIENT_VERSION)) {
+            additionalProperties.put(STTP_CLIENT_VERSION, STTP_CLIENT_VERSION_DEFAULT);
+        }
 
         supportingFiles.clear();
         supportingFiles.add(new SupportingFile("README.mustache", "", "README.md"));
diff --git a/modules/openapi-generator/src/main/resources/scala-sttp/build.sbt.mustache b/modules/openapi-generator/src/main/resources/scala-sttp/build.sbt.mustache
index f20a44d2ea9..06abfb89db6 100644
--- a/modules/openapi-generator/src/main/resources/scala-sttp/build.sbt.mustache
+++ b/modules/openapi-generator/src/main/resources/scala-sttp/build.sbt.mustache
@@ -7,15 +7,12 @@ scalaVersion := "2.13.2"
 crossScalaVersions := Seq(scalaVersion.value, "2.12.10",  "2.11.12")
 
 libraryDependencies ++= Seq(
-  "com.softwaremill.sttp.client" %% "core" % "2.1.5",
-  "com.softwaremill.sttp.client" %% "json4s" % "2.1.5",
+  "com.softwaremill.sttp.client" %% "core" % "{{sttpClientVersion}}",
+  "com.softwaremill.sttp.client" %% "json4s" % "{{sttpClientVersion}}",
 {{#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"
+  "org.json4s" %% "json4s-jackson" % "3.6.7"
 )
 
 scalacOptions := Seq(
diff --git a/samples/client/petstore/scala-sttp/build.sbt b/samples/client/petstore/scala-sttp/build.sbt
index 91a042edafb..59d507c29f2 100644
--- a/samples/client/petstore/scala-sttp/build.sbt
+++ b/samples/client/petstore/scala-sttp/build.sbt
@@ -4,21 +4,14 @@ organization := "org.openapitools"
 
 scalaVersion := "2.13.2"
 
-crossScalaVersions := Seq(scalaVersion.value, "2.12.10",  "2.11.12")
+crossScalaVersions := Seq(scalaVersion.value, "2.12.10", "2.11.12")
 
 libraryDependencies ++= Seq(
   "com.softwaremill.sttp.client" %% "core" % "2.1.5",
   "com.softwaremill.sttp.client" %% "json4s" % "2.1.5",
-  "org.json4s" %% "json4s-jackson" % "3.6.7",
-  // test dependencies
-  "org.scalatest" %% "scalatest" % "3.0.8" % Test,
-  "junit" % "junit" % "4.13" % "test"
+  "org.json4s" %% "json4s-jackson" % "3.6.7"
 )
 
-scalacOptions := Seq(
-  "-unchecked",
-  "-deprecation",
-  "-feature"
-)
+scalacOptions := Seq("-unchecked", "-deprecation", "-feature")
 
 publishArtifact in (Compile, packageDoc) := false
-- 
GitLab


From 4ac88948881c79431077e4a1cca2ebdcedb1aa08 Mon Sep 17 00:00:00 2001
From: ghostbuster91 <kghost0@gmail.com>
Date: Thu, 4 Jun 2020 16:05:28 +0200
Subject: [PATCH 05/38] Add option to return errors in terms of monadError

---
 .../languages/ScalaSttpClientCodegen.java     |   9 +
 .../main/resources/scala-sttp/api.mustache    |   4 +-
 .../resources/scala-sttp/build.sbt.mustache   |   2 +-
 samples/client/petstore/scala-sttp/build.sbt  |   8 +-
 .../org/openapitools/client/api/PetApi.scala  | 196 ++++++++--------
 .../openapitools/client/api/StoreApi.scala    | 103 +++++----
 .../org/openapitools/client/api/UserApi.scala | 209 ++++++++++--------
 7 files changed, 295 insertions(+), 236 deletions(-)

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
index e1cde845033..7aae7d3b366 100644
--- 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
@@ -33,6 +33,12 @@ public class ScalaSttpClientCodegen extends ScalaAkkaClientCodegen implements Co
     public static final String STTP_CLIENT_VERSION_DESC = "The version of stpp client";
     public static final String STTP_CLIENT_VERSION_DEFAULT = "2.1.5";
 
+    public static final String SEPARATE_ERROR_CHANNEL = "separateErrorChannel";
+    public static final String SEPARATE_ERROR_CHANNEL_DESC = "Whether to return response as " +
+            "F[Either[ResponseError[ErrorType], ReturnType]]] or to flatten " +
+            "response's error raising them through enclosing monad (F[ReturnType]).";
+    public static final Boolean SEPARATE_ERROR_CHANNEL_DEFAULT = true;
+
     public ScalaSttpClientCodegen() {
         super();
         generatorMetadata = GeneratorMetadata.newBuilder(generatorMetadata)
@@ -43,6 +49,7 @@ public class ScalaSttpClientCodegen extends ScalaAkkaClientCodegen implements Co
         outputFolder = "generated-code/scala-sttp";
 
         cliOptions.add(CliOption.newString(STTP_CLIENT_VERSION,STTP_CLIENT_VERSION_DESC).defaultValue(STTP_CLIENT_VERSION_DEFAULT));
+        cliOptions.add(CliOption.newBoolean(SEPARATE_ERROR_CHANNEL, SEPARATE_ERROR_CHANNEL_DESC, SEPARATE_ERROR_CHANNEL_DEFAULT));
     }
 
     @Override
@@ -60,6 +67,8 @@ public class ScalaSttpClientCodegen extends ScalaAkkaClientCodegen implements Co
         if(!additionalProperties.containsKey(STTP_CLIENT_VERSION)) {
             additionalProperties.put(STTP_CLIENT_VERSION, STTP_CLIENT_VERSION_DEFAULT);
         }
+        Object separateErrorChannel = additionalProperties.getOrDefault(SEPARATE_ERROR_CHANNEL, SEPARATE_ERROR_CHANNEL_DEFAULT);
+        additionalProperties.put(SEPARATE_ERROR_CHANNEL, Boolean.valueOf(separateErrorChannel.toString()));
 
         supportingFiles.clear();
         supportingFiles.add(new SupportingFile("README.mustache", "", "README.md"));
diff --git a/modules/openapi-generator/src/main/resources/scala-sttp/api.mustache b/modules/openapi-generator/src/main/resources/scala-sttp/api.mustache
index 23f75ae483c..11752358a1a 100644
--- a/modules/openapi-generator/src/main/resources/scala-sttp/api.mustache
+++ b/modules/openapi-generator/src/main/resources/scala-sttp/api.mustache
@@ -22,7 +22,7 @@ class {{classname}}(baseUrl: String)(implicit serializer: SttpSerializer) {
 {{#javadocRenderer}}
 {{>javadoc}}
 {{/javadocRenderer}}
-  def {{operationId}}({{>methodParameters}}): Request[Either[ResponseError[Exception], {{>operationReturnType}}], Nothing] =
+  def {{operationId}}({{>methodParameters}}): Request[{{#separateErrorChannel}}Either[ResponseError[Exception], {{>operationReturnType}}]{{/separateErrorChannel}}{{^separateErrorChannel}}{{>operationReturnType}}{{/separateErrorChannel}}, Nothing] =
     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}}
@@ -35,7 +35,7 @@ class {{classname}}(baseUrl: String)(implicit serializer: SttpSerializer) {
         {{>paramFormCreation}}{{#hasMore}}, {{/hasMore}}{{/formParams}}
       )){{/formParams.0}}{{#bodyParam}}
       .body({{paramName}}){{/bodyParam}}
-      .response(asJson[{{>operationReturnType}}])
+      .response({{#separateErrorChannel}}asJson{{/separateErrorChannel}}{{^separateErrorChannel}}asJsonAlwaysUnsafe{{/separateErrorChannel}}[{{>operationReturnType}}])
 
 {{/operation}}
 }
diff --git a/modules/openapi-generator/src/main/resources/scala-sttp/build.sbt.mustache b/modules/openapi-generator/src/main/resources/scala-sttp/build.sbt.mustache
index 06abfb89db6..4d21d2409f5 100644
--- a/modules/openapi-generator/src/main/resources/scala-sttp/build.sbt.mustache
+++ b/modules/openapi-generator/src/main/resources/scala-sttp/build.sbt.mustache
@@ -4,7 +4,7 @@ organization := "{{groupId}}"
 
 scalaVersion := "2.13.2"
 
-crossScalaVersions := Seq(scalaVersion.value, "2.12.10",  "2.11.12")
+crossScalaVersions := Seq(scalaVersion.value, "2.12.10", "2.11.12")
 
 libraryDependencies ++= Seq(
   "com.softwaremill.sttp.client" %% "core" % "{{sttpClientVersion}}",
diff --git a/samples/client/petstore/scala-sttp/build.sbt b/samples/client/petstore/scala-sttp/build.sbt
index 59d507c29f2..12fec5f6a0c 100644
--- a/samples/client/petstore/scala-sttp/build.sbt
+++ b/samples/client/petstore/scala-sttp/build.sbt
@@ -4,7 +4,7 @@ organization := "org.openapitools"
 
 scalaVersion := "2.13.2"
 
-crossScalaVersions := Seq(scalaVersion.value, "2.12.10", "2.11.12")
+crossScalaVersions := Seq(scalaVersion.value, "2.12.10",  "2.11.12")
 
 libraryDependencies ++= Seq(
   "com.softwaremill.sttp.client" %% "core" % "2.1.5",
@@ -12,6 +12,10 @@ libraryDependencies ++= Seq(
   "org.json4s" %% "json4s-jackson" % "3.6.7"
 )
 
-scalacOptions := Seq("-unchecked", "-deprecation", "-feature")
+scalacOptions := Seq(
+  "-unchecked",
+  "-deprecation",
+  "-feature"
+)
 
 publishArtifact in (Compile, packageDoc) := false
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
index 159b68ea86a..ee5916291e2 100644
--- 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
@@ -1,14 +1,14 @@
 /**
- * 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.
- */
+  * 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
@@ -20,7 +20,9 @@ import sttp.model.Method
 
 object PetApi {
 
-  def apply(baseUrl: String = "http://petstore.swagger.io/v2")(implicit serializer: SttpSerializer) = new PetApi(baseUrl)
+  def apply(baseUrl: String = "http://petstore.swagger.io/v2")(
+    implicit serializer: SttpSerializer
+  ) = new PetApi(baseUrl)
 }
 
 class PetApi(baseUrl: String)(implicit serializer: SttpSerializer) {
@@ -28,13 +30,15 @@ class PetApi(baseUrl: String)(implicit serializer: SttpSerializer) {
   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): Request[Either[ResponseError[Exception], Pet], Nothing] =
+    * 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
+  ): Request[Either[ResponseError[Exception], Pet], Nothing] =
     basicRequest
       .method(Method.POST, uri"$baseUrl/pet")
       .contentType("application/json")
@@ -42,13 +46,16 @@ class PetApi(baseUrl: String)(implicit serializer: SttpSerializer) {
       .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): Request[Either[ResponseError[Exception], Unit], Nothing] =
+    * Expected answers:
+    *   code 400 :  (Invalid pet value)
+    *
+    * @param petId Pet id to delete
+    * @param apiKey
+    */
+  def deletePet(
+    petId: Long,
+    apiKey: Option[String] = None
+  ): Request[Either[ResponseError[Exception], Unit], Nothing] =
     basicRequest
       .method(Method.DELETE, uri"$baseUrl/pet/${petId}")
       .contentType("application/json")
@@ -56,49 +63,55 @@ class PetApi(baseUrl: String)(implicit serializer: SttpSerializer) {
       .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]): Request[Either[ResponseError[Exception], Seq[Pet]], Nothing] =
+    * 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]
+  ): Request[Either[ResponseError[Exception], Seq[Pet]], Nothing] =
     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]): Request[Either[ResponseError[Exception], Seq[Pet]], Nothing] =
+    * 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]
+  ): Request[Either[ResponseError[Exception], Seq[Pet]], Nothing] =
     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): Request[Either[ResponseError[Exception], Pet], Nothing] =
+    * 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
+  ): Request[Either[ResponseError[Exception], Pet], Nothing] =
     basicRequest
       .method(Method.GET, uri"$baseUrl/pet/${petId}")
       .contentType("application/json")
@@ -106,15 +119,17 @@ class PetApi(baseUrl: String)(implicit serializer: SttpSerializer) {
       .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): Request[Either[ResponseError[Exception], Pet], Nothing] =
+    * 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
+  ): Request[Either[ResponseError[Exception], Pet], Nothing] =
     basicRequest
       .method(Method.PUT, uri"$baseUrl/pet")
       .contentType("application/json")
@@ -122,40 +137,41 @@ class PetApi(baseUrl: String)(implicit serializer: SttpSerializer) {
       .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): Request[Either[ResponseError[Exception], Unit], Nothing] =
+    * 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
+  ): Request[Either[ResponseError[Exception], Unit], Nothing] =
     basicRequest
       .method(Method.POST, uri"$baseUrl/pet/${petId}")
       .contentType("application/x-www-form-urlencoded")
-      .body(Map(
-        "name" -> name, 
-        "status" -> status
-      ))
+      .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): Request[Either[ResponseError[Exception], ApiResponse], Nothing] =
+    * 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
+  ): Request[Either[ResponseError[Exception], ApiResponse], Nothing] =
     basicRequest
       .method(Method.POST, uri"$baseUrl/pet/${petId}/uploadImage")
       .contentType("multipart/form-data")
-      .body(Map(
-        "additionalMetadata" -> additionalMetadata, 
-        "file" -> file
-      ))
+      .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
index 2345bdf5508..b4518c2863d 100644
--- 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
@@ -1,14 +1,14 @@
 /**
- * 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.
- */
+  * 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
@@ -18,7 +18,9 @@ import sttp.model.Method
 
 object StoreApi {
 
-  def apply(baseUrl: String = "http://petstore.swagger.io/v2")(implicit serializer: SttpSerializer) = new StoreApi(baseUrl)
+  def apply(baseUrl: String = "http://petstore.swagger.io/v2")(
+    implicit serializer: SttpSerializer
+  ) = new StoreApi(baseUrl)
 }
 
 class StoreApi(baseUrl: String)(implicit serializer: SttpSerializer) {
@@ -26,30 +28,34 @@ class StoreApi(baseUrl: String)(implicit serializer: SttpSerializer) {
   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): Request[Either[ResponseError[Exception], Unit], Nothing] =
+    * 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
+  ): Request[Either[ResponseError[Exception], Unit], Nothing] =
     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): Request[Either[ResponseError[Exception], Map[String, Int]], Nothing] =
+    * 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
+  ): Request[Either[ResponseError[Exception], Map[String, Int]], Nothing] =
     basicRequest
       .method(Method.GET, uri"$baseUrl/store/inventory")
       .contentType("application/json")
@@ -57,29 +63,33 @@ class StoreApi(baseUrl: String)(implicit serializer: SttpSerializer) {
       .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): Request[Either[ResponseError[Exception], Order], Nothing] =
+    * 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
+  ): Request[Either[ResponseError[Exception], Order], Nothing] =
     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): Request[Either[ResponseError[Exception], Order], Nothing] =
+    * Expected answers:
+    *   code 200 : Order (successful operation)
+    *   code 400 :  (Invalid Order)
+    *
+    * @param order order placed for purchasing the pet
+    */
+  def placeOrder(
+    order: Order
+  ): Request[Either[ResponseError[Exception], Order], Nothing] =
     basicRequest
       .method(Method.POST, uri"$baseUrl/store/order")
       .contentType("application/json")
@@ -87,4 +97,3 @@ class StoreApi(baseUrl: String)(implicit serializer: SttpSerializer) {
       .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
index 4a36ce95949..4d24fc6f6c3 100644
--- 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
@@ -1,14 +1,14 @@
 /**
- * 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.
- */
+  * 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
@@ -18,7 +18,9 @@ import sttp.model.Method
 
 object UserApi {
 
-  def apply(baseUrl: String = "http://petstore.swagger.io/v2")(implicit serializer: SttpSerializer) = new UserApi(baseUrl)
+  def apply(baseUrl: String = "http://petstore.swagger.io/v2")(
+    implicit serializer: SttpSerializer
+  ) = new UserApi(baseUrl)
 }
 
 class UserApi(baseUrl: String)(implicit serializer: SttpSerializer) {
@@ -26,17 +28,19 @@ class UserApi(baseUrl: String)(implicit serializer: SttpSerializer) {
   import serializer._
 
   /**
-   * This can only be done by the logged in user.
-   * 
-   * Expected answers:
-   *   code 0 :  (successful operation)
-   * 
-   * Available security schemes:
-   *   api_key (apiKey)
-   * 
-   * @param user Created user object
-   */
-  def createUser(user: User)(implicit apiKey: ApiKeyValue): Request[Either[ResponseError[Exception], Unit], Nothing] =
+    * This can only be done by the logged in user.
+    *
+    * Expected answers:
+    *   code 0 :  (successful operation)
+    *
+    * Available security schemes:
+    *   api_key (apiKey)
+    *
+    * @param user Created user object
+    */
+  def createUser(user: User)(
+    implicit apiKey: ApiKeyValue
+  ): Request[Either[ResponseError[Exception], Unit], Nothing] =
     basicRequest
       .method(Method.POST, uri"$baseUrl/user")
       .contentType("application/json")
@@ -45,15 +49,17 @@ class UserApi(baseUrl: String)(implicit serializer: SttpSerializer) {
       .response(asJson[Unit])
 
   /**
-   * Expected answers:
-   *   code 0 :  (successful operation)
-   * 
-   * Available security schemes:
-   *   api_key (apiKey)
-   * 
-   * @param user List of user object
-   */
-  def createUsersWithArrayInput(user: Seq[User])(implicit apiKey: ApiKeyValue): Request[Either[ResponseError[Exception], Unit], Nothing] =
+    * Expected answers:
+    *   code 0 :  (successful operation)
+    *
+    * Available security schemes:
+    *   api_key (apiKey)
+    *
+    * @param user List of user object
+    */
+  def createUsersWithArrayInput(user: Seq[User])(
+    implicit apiKey: ApiKeyValue
+  ): Request[Either[ResponseError[Exception], Unit], Nothing] =
     basicRequest
       .method(Method.POST, uri"$baseUrl/user/createWithArray")
       .contentType("application/json")
@@ -62,15 +68,17 @@ class UserApi(baseUrl: String)(implicit serializer: SttpSerializer) {
       .response(asJson[Unit])
 
   /**
-   * Expected answers:
-   *   code 0 :  (successful operation)
-   * 
-   * Available security schemes:
-   *   api_key (apiKey)
-   * 
-   * @param user List of user object
-   */
-  def createUsersWithListInput(user: Seq[User])(implicit apiKey: ApiKeyValue): Request[Either[ResponseError[Exception], Unit], Nothing] =
+    * Expected answers:
+    *   code 0 :  (successful operation)
+    *
+    * Available security schemes:
+    *   api_key (apiKey)
+    *
+    * @param user List of user object
+    */
+  def createUsersWithListInput(user: Seq[User])(
+    implicit apiKey: ApiKeyValue
+  ): Request[Either[ResponseError[Exception], Unit], Nothing] =
     basicRequest
       .method(Method.POST, uri"$baseUrl/user/createWithList")
       .contentType("application/json")
@@ -79,18 +87,20 @@ class UserApi(baseUrl: String)(implicit serializer: SttpSerializer) {
       .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:
-   *   api_key (apiKey)
-   * 
-   * @param username The name that needs to be deleted
-   */
-  def deleteUser(username: String)(implicit apiKey: ApiKeyValue): Request[Either[ResponseError[Exception], Unit], Nothing] =
+    * 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:
+    *   api_key (apiKey)
+    *
+    * @param username The name that needs to be deleted
+    */
+  def deleteUser(username: String)(
+    implicit apiKey: ApiKeyValue
+  ): Request[Either[ResponseError[Exception], Unit], Nothing] =
     basicRequest
       .method(Method.DELETE, uri"$baseUrl/user/${username}")
       .contentType("application/json")
@@ -98,45 +108,55 @@ class UserApi(baseUrl: String)(implicit serializer: SttpSerializer) {
       .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): Request[Either[ResponseError[Exception], User], Nothing] =
+    * 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
+  ): Request[Either[ResponseError[Exception], User], Nothing] =
     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 `api_key` 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): Request[Either[ResponseError[Exception], String], Nothing] =
+    * Expected answers:
+    *   code 200 : String (successful operation)
+    *              Headers :
+    *                Set-Cookie - Cookie authentication key for use with the `api_key` 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
+  ): Request[Either[ResponseError[Exception], String], Nothing] =
     basicRequest
-      .method(Method.GET, uri"$baseUrl/user/login?username=$username&password=$password")
+      .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:
-   *   api_key (apiKey)
-   */
-  def logoutUser()(implicit apiKey: ApiKeyValue): Request[Either[ResponseError[Exception], Unit], Nothing] =
+    * Expected answers:
+    *   code 0 :  (successful operation)
+    *
+    * Available security schemes:
+    *   api_key (apiKey)
+    */
+  def logoutUser()(
+    implicit apiKey: ApiKeyValue
+  ): Request[Either[ResponseError[Exception], Unit], Nothing] =
     basicRequest
       .method(Method.GET, uri"$baseUrl/user/logout")
       .contentType("application/json")
@@ -144,19 +164,21 @@ class UserApi(baseUrl: String)(implicit serializer: SttpSerializer) {
       .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:
-   *   api_key (apiKey)
-   * 
-   * @param username name that need to be deleted
-   * @param user Updated user object
-   */
-  def updateUser(username: String, user: User)(implicit apiKey: ApiKeyValue): Request[Either[ResponseError[Exception], Unit], Nothing] =
+    * 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:
+    *   api_key (apiKey)
+    *
+    * @param username name that need to be deleted
+    * @param user Updated user object
+    */
+  def updateUser(username: String, user: User)(
+    implicit apiKey: ApiKeyValue
+  ): Request[Either[ResponseError[Exception], Unit], Nothing] =
     basicRequest
       .method(Method.PUT, uri"$baseUrl/user/${username}")
       .contentType("application/json")
@@ -165,4 +187,3 @@ class UserApi(baseUrl: String)(implicit serializer: SttpSerializer) {
       .response(asJson[Unit])
 
 }
-
-- 
GitLab


From 88908e29dc71a86de7da2e959a9bb3396955f4e1 Mon Sep 17 00:00:00 2001
From: ghostbuster91 <kghost0@gmail.com>
Date: Thu, 4 Jun 2020 16:08:29 +0200
Subject: [PATCH 06/38] Add option to customize jodaTime version

---
 .../codegen/languages/ScalaSttpClientCodegen.java      | 10 +++++++++-
 .../src/main/resources/scala-sttp/build.sbt.mustache   |  2 +-
 2 files changed, 10 insertions(+), 2 deletions(-)

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
index 7aae7d3b366..5d79adf760e 100644
--- 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
@@ -30,7 +30,7 @@ import java.util.List;
 
 public class ScalaSttpClientCodegen extends ScalaAkkaClientCodegen implements CodegenConfig {
     public static final String STTP_CLIENT_VERSION = "sttpClientVersion";
-    public static final String STTP_CLIENT_VERSION_DESC = "The version of stpp client";
+    public static final String STTP_CLIENT_VERSION_DESC = "The version of sttp client";
     public static final String STTP_CLIENT_VERSION_DEFAULT = "2.1.5";
 
     public static final String SEPARATE_ERROR_CHANNEL = "separateErrorChannel";
@@ -39,6 +39,10 @@ public class ScalaSttpClientCodegen extends ScalaAkkaClientCodegen implements Co
             "response's error raising them through enclosing monad (F[ReturnType]).";
     public static final Boolean SEPARATE_ERROR_CHANNEL_DEFAULT = true;
 
+    public static final String JODA_TIME_VERSION= "jodaTimeVersion";
+    public static final String JODA_TIME_VERSION_DESC = "The version of joda-time library";
+    public static final String JODA_TIME_VERSION_DEFAULT = "2.10.6";
+
     public ScalaSttpClientCodegen() {
         super();
         generatorMetadata = GeneratorMetadata.newBuilder(generatorMetadata)
@@ -49,6 +53,7 @@ public class ScalaSttpClientCodegen extends ScalaAkkaClientCodegen implements Co
         outputFolder = "generated-code/scala-sttp";
 
         cliOptions.add(CliOption.newString(STTP_CLIENT_VERSION,STTP_CLIENT_VERSION_DESC).defaultValue(STTP_CLIENT_VERSION_DEFAULT));
+        cliOptions.add(CliOption.newString(JODA_TIME_VERSION,JODA_TIME_VERSION_DESC).defaultValue(JODA_TIME_VERSION_DEFAULT));
         cliOptions.add(CliOption.newBoolean(SEPARATE_ERROR_CHANNEL, SEPARATE_ERROR_CHANNEL_DESC, SEPARATE_ERROR_CHANNEL_DEFAULT));
     }
 
@@ -67,6 +72,9 @@ public class ScalaSttpClientCodegen extends ScalaAkkaClientCodegen implements Co
         if(!additionalProperties.containsKey(STTP_CLIENT_VERSION)) {
             additionalProperties.put(STTP_CLIENT_VERSION, STTP_CLIENT_VERSION_DEFAULT);
         }
+        if(!additionalProperties.containsKey(JODA_TIME_VERSION)) {
+            additionalProperties.put(JODA_TIME_VERSION, JODA_TIME_VERSION_DEFAULT);
+        }
         Object separateErrorChannel = additionalProperties.getOrDefault(SEPARATE_ERROR_CHANNEL, SEPARATE_ERROR_CHANNEL_DEFAULT);
         additionalProperties.put(SEPARATE_ERROR_CHANNEL, Boolean.valueOf(separateErrorChannel.toString()));
 
diff --git a/modules/openapi-generator/src/main/resources/scala-sttp/build.sbt.mustache b/modules/openapi-generator/src/main/resources/scala-sttp/build.sbt.mustache
index 4d21d2409f5..a5f13ac3b0a 100644
--- a/modules/openapi-generator/src/main/resources/scala-sttp/build.sbt.mustache
+++ b/modules/openapi-generator/src/main/resources/scala-sttp/build.sbt.mustache
@@ -10,7 +10,7 @@ libraryDependencies ++= Seq(
   "com.softwaremill.sttp.client" %% "core" % "{{sttpClientVersion}}",
   "com.softwaremill.sttp.client" %% "json4s" % "{{sttpClientVersion}}",
 {{#joda}}
-  "joda-time" % "joda-time" % "2.10.1",
+  "joda-time" % "joda-time" % "{{jodaTimeVersion}}",
 {{/joda}}
   "org.json4s" %% "json4s-jackson" % "3.6.7"
 )
-- 
GitLab


From 5c255e49f436356bc613220ba0e7ff6f7346030c Mon Sep 17 00:00:00 2001
From: ghostbuster91 <kghost0@gmail.com>
Date: Thu, 4 Jun 2020 16:12:06 +0200
Subject: [PATCH 07/38] Add option to customize json4s version

---
 .../codegen/languages/ScalaSttpClientCodegen.java  | 14 +++++++++++---
 .../main/resources/scala-sttp/build.sbt.mustache   |  2 +-
 2 files changed, 12 insertions(+), 4 deletions(-)

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
index 5d79adf760e..e7dd8b7dd35 100644
--- 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
@@ -39,10 +39,14 @@ public class ScalaSttpClientCodegen extends ScalaAkkaClientCodegen implements Co
             "response's error raising them through enclosing monad (F[ReturnType]).";
     public static final Boolean SEPARATE_ERROR_CHANNEL_DEFAULT = true;
 
-    public static final String JODA_TIME_VERSION= "jodaTimeVersion";
+    public static final String JODA_TIME_VERSION = "jodaTimeVersion";
     public static final String JODA_TIME_VERSION_DESC = "The version of joda-time library";
     public static final String JODA_TIME_VERSION_DEFAULT = "2.10.6";
 
+    public static final String JSON4S_VERSION = "json4sVersion";
+    public static final String JSON4S_VERSION_DESC = "The version of json4s library";
+    public static final String JSON4S_VERSION_DEFAULT = "3.6.8";
+
     public ScalaSttpClientCodegen() {
         super();
         generatorMetadata = GeneratorMetadata.newBuilder(generatorMetadata)
@@ -52,8 +56,9 @@ public class ScalaSttpClientCodegen extends ScalaAkkaClientCodegen implements Co
         embeddedTemplateDir = templateDir = "scala-sttp";
         outputFolder = "generated-code/scala-sttp";
 
-        cliOptions.add(CliOption.newString(STTP_CLIENT_VERSION,STTP_CLIENT_VERSION_DESC).defaultValue(STTP_CLIENT_VERSION_DEFAULT));
-        cliOptions.add(CliOption.newString(JODA_TIME_VERSION,JODA_TIME_VERSION_DESC).defaultValue(JODA_TIME_VERSION_DEFAULT));
+        cliOptions.add(CliOption.newString(STTP_CLIENT_VERSION, STTP_CLIENT_VERSION_DESC).defaultValue(STTP_CLIENT_VERSION_DEFAULT));
+        cliOptions.add(CliOption.newString(JODA_TIME_VERSION, JODA_TIME_VERSION_DESC).defaultValue(JODA_TIME_VERSION_DEFAULT));
+        cliOptions.add(CliOption.newString(JSON4S_VERSION, JSON4S_VERSION_DESC).defaultValue(JSON4S_VERSION_DEFAULT));
         cliOptions.add(CliOption.newBoolean(SEPARATE_ERROR_CHANNEL, SEPARATE_ERROR_CHANNEL_DESC, SEPARATE_ERROR_CHANNEL_DEFAULT));
     }
 
@@ -75,6 +80,9 @@ public class ScalaSttpClientCodegen extends ScalaAkkaClientCodegen implements Co
         if(!additionalProperties.containsKey(JODA_TIME_VERSION)) {
             additionalProperties.put(JODA_TIME_VERSION, JODA_TIME_VERSION_DEFAULT);
         }
+        if(!additionalProperties.containsKey(JSON4S_VERSION)) {
+            additionalProperties.put(JSON4S_VERSION, JSON4S_VERSION_DEFAULT);
+        }
         Object separateErrorChannel = additionalProperties.getOrDefault(SEPARATE_ERROR_CHANNEL, SEPARATE_ERROR_CHANNEL_DEFAULT);
         additionalProperties.put(SEPARATE_ERROR_CHANNEL, Boolean.valueOf(separateErrorChannel.toString()));
 
diff --git a/modules/openapi-generator/src/main/resources/scala-sttp/build.sbt.mustache b/modules/openapi-generator/src/main/resources/scala-sttp/build.sbt.mustache
index a5f13ac3b0a..13c0e513433 100644
--- a/modules/openapi-generator/src/main/resources/scala-sttp/build.sbt.mustache
+++ b/modules/openapi-generator/src/main/resources/scala-sttp/build.sbt.mustache
@@ -12,7 +12,7 @@ libraryDependencies ++= Seq(
 {{#joda}}
   "joda-time" % "joda-time" % "{{jodaTimeVersion}}",
 {{/joda}}
-  "org.json4s" %% "json4s-jackson" % "3.6.7"
+  "org.json4s" %% "json4s-jackson" % "{{json4sVersion}}"
 )
 
 scalacOptions := Seq(
-- 
GitLab


From 6c5d7920dedfc77c67b6dd4c511915340e955af2 Mon Sep 17 00:00:00 2001
From: ghostbuster91 <kghost0@gmail.com>
Date: Thu, 4 Jun 2020 16:31:32 +0200
Subject: [PATCH 08/38] Simplify jsonHandling

---
 .../main/resources/scala-sttp/api.mustache    |  10 +-
 .../resources/scala-sttp/apiInvoker.mustache  |   7 +-
 samples/client/petstore/scala-sttp/build.sbt  |   4 +-
 .../org/openapitools/client/api/PetApi.scala  |  13 +-
 .../openapitools/client/api/StoreApi.scala    | 111 ++++-----
 .../org/openapitools/client/api/UserApi.scala | 217 ++++++++----------
 .../openapitools/client/core/ApiInvoker.scala |   7 +-
 7 files changed, 157 insertions(+), 212 deletions(-)

diff --git a/modules/openapi-generator/src/main/resources/scala-sttp/api.mustache b/modules/openapi-generator/src/main/resources/scala-sttp/api.mustache
index 11752358a1a..2241ae64d2b 100644
--- a/modules/openapi-generator/src/main/resources/scala-sttp/api.mustache
+++ b/modules/openapi-generator/src/main/resources/scala-sttp/api.mustache
@@ -5,18 +5,12 @@ package {{package}}
 import {{import}}
 {{/imports}}
 import {{invokerPackage}}._
+import {{invokerPackage}}.JsonSupport._
 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 serializer._
+class {{classname}}(baseUrl: String = "{{{basePath}}}") {
 
 {{#operation}}
 {{#javadocRenderer}}
diff --git a/modules/openapi-generator/src/main/resources/scala-sttp/apiInvoker.mustache b/modules/openapi-generator/src/main/resources/scala-sttp/apiInvoker.mustache
index a6947991634..b2487a79b2f 100644
--- a/modules/openapi-generator/src/main/resources/scala-sttp/apiInvoker.mustache
+++ b/modules/openapi-generator/src/main/resources/scala-sttp/apiInvoker.mustache
@@ -6,9 +6,10 @@ import sttp.client._
 import {{{apiPackage}}}.EnumsSerializers
 import sttp.client.json4s.SttpJson4sApi
 
-class SttpSerializer(implicit val format: Formats = DefaultFormats ++ EnumsSerializers.all ++ Serializers.all,
-                     implicit val serialization: org.json4s.Serialization = org.json4s.jackson.Serialization) extends SttpJson4sApi
-
+object JsonSupport extends SttpJson4sApi {
+  implicit val format: Formats = DefaultFormats ++ EnumsSerializers.all ++ Serializers.all
+  implicit val serialization: org.json4s.Serialization = org.json4s.jackson.Serialization
+}
 
 object Helpers {
 
diff --git a/samples/client/petstore/scala-sttp/build.sbt b/samples/client/petstore/scala-sttp/build.sbt
index 12fec5f6a0c..e9dd062cdcb 100644
--- a/samples/client/petstore/scala-sttp/build.sbt
+++ b/samples/client/petstore/scala-sttp/build.sbt
@@ -4,12 +4,12 @@ organization := "org.openapitools"
 
 scalaVersion := "2.13.2"
 
-crossScalaVersions := Seq(scalaVersion.value, "2.12.10",  "2.11.12")
+crossScalaVersions := Seq(scalaVersion.value, "2.12.10", "2.11.12")
 
 libraryDependencies ++= Seq(
   "com.softwaremill.sttp.client" %% "core" % "2.1.5",
   "com.softwaremill.sttp.client" %% "json4s" % "2.1.5",
-  "org.json4s" %% "json4s-jackson" % "3.6.7"
+  "org.json4s" %% "json4s-jackson" % "3.6.8"
 )
 
 scalacOptions := Seq(
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
index ee5916291e2..3420eaf9d60 100644
--- 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
@@ -15,19 +15,11 @@ import org.openapitools.client.model.ApiResponse
 import java.io.File
 import org.openapitools.client.model.Pet
 import org.openapitools.client.core._
+import org.openapitools.client.core.JsonSupport._
 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 serializer._
+class PetApi(baseUrl: String = "http://petstore.swagger.io/v2") {
 
   /**
     * Expected answers:
@@ -59,7 +51,6 @@ class PetApi(baseUrl: String)(implicit serializer: SttpSerializer) {
     basicRequest
       .method(Method.DELETE, uri"$baseUrl/pet/${petId}")
       .contentType("application/json")
-      .header("api_key", apiKey)
       .response(asJson[Unit])
 
   /**
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
index b4518c2863d..8d78087626a 100644
--- 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
@@ -1,61 +1,49 @@
 /**
-  * 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.
-  */
+ * 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 org.openapitools.client.core.JsonSupport._
 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 serializer._
+class StoreApi(baseUrl: String = "http://petstore.swagger.io/v2") {
 
   /**
-    * 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
-  ): Request[Either[ResponseError[Exception], Unit], Nothing] =
+   * 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): Request[Either[ResponseError[Exception], Unit], Nothing] =
     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
-  ): Request[Either[ResponseError[Exception], Map[String, Int]], Nothing] =
+   * 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): Request[Either[ResponseError[Exception], Map[String, Int]], Nothing] =
     basicRequest
       .method(Method.GET, uri"$baseUrl/store/inventory")
       .contentType("application/json")
@@ -63,33 +51,29 @@ class StoreApi(baseUrl: String)(implicit serializer: SttpSerializer) {
       .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
-  ): Request[Either[ResponseError[Exception], Order], Nothing] =
+   * 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): Request[Either[ResponseError[Exception], Order], Nothing] =
     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
-  ): Request[Either[ResponseError[Exception], Order], Nothing] =
+   * Expected answers:
+   *   code 200 : Order (successful operation)
+   *   code 400 :  (Invalid Order)
+   * 
+   * @param order order placed for purchasing the pet
+   */
+  def placeOrder(order: Order): Request[Either[ResponseError[Exception], Order], Nothing] =
     basicRequest
       .method(Method.POST, uri"$baseUrl/store/order")
       .contentType("application/json")
@@ -97,3 +81,4 @@ class StoreApi(baseUrl: String)(implicit serializer: SttpSerializer) {
       .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
index 4d24fc6f6c3..b57cf699ad7 100644
--- 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
@@ -1,46 +1,36 @@
 /**
-  * 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.
-  */
+ * 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 org.openapitools.client.core.JsonSupport._
 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 serializer._
+class UserApi(baseUrl: String = "http://petstore.swagger.io/v2") {
 
   /**
-    * This can only be done by the logged in user.
-    *
-    * Expected answers:
-    *   code 0 :  (successful operation)
-    *
-    * Available security schemes:
-    *   api_key (apiKey)
-    *
-    * @param user Created user object
-    */
-  def createUser(user: User)(
-    implicit apiKey: ApiKeyValue
-  ): Request[Either[ResponseError[Exception], Unit], Nothing] =
+   * This can only be done by the logged in user.
+   * 
+   * Expected answers:
+   *   code 0 :  (successful operation)
+   * 
+   * Available security schemes:
+   *   api_key (apiKey)
+   * 
+   * @param user Created user object
+   */
+  def createUser(user: User)(implicit apiKey: ApiKeyValue): Request[Either[ResponseError[Exception], Unit], Nothing] =
     basicRequest
       .method(Method.POST, uri"$baseUrl/user")
       .contentType("application/json")
@@ -49,17 +39,15 @@ class UserApi(baseUrl: String)(implicit serializer: SttpSerializer) {
       .response(asJson[Unit])
 
   /**
-    * Expected answers:
-    *   code 0 :  (successful operation)
-    *
-    * Available security schemes:
-    *   api_key (apiKey)
-    *
-    * @param user List of user object
-    */
-  def createUsersWithArrayInput(user: Seq[User])(
-    implicit apiKey: ApiKeyValue
-  ): Request[Either[ResponseError[Exception], Unit], Nothing] =
+   * Expected answers:
+   *   code 0 :  (successful operation)
+   * 
+   * Available security schemes:
+   *   api_key (apiKey)
+   * 
+   * @param user List of user object
+   */
+  def createUsersWithArrayInput(user: Seq[User])(implicit apiKey: ApiKeyValue): Request[Either[ResponseError[Exception], Unit], Nothing] =
     basicRequest
       .method(Method.POST, uri"$baseUrl/user/createWithArray")
       .contentType("application/json")
@@ -68,17 +56,15 @@ class UserApi(baseUrl: String)(implicit serializer: SttpSerializer) {
       .response(asJson[Unit])
 
   /**
-    * Expected answers:
-    *   code 0 :  (successful operation)
-    *
-    * Available security schemes:
-    *   api_key (apiKey)
-    *
-    * @param user List of user object
-    */
-  def createUsersWithListInput(user: Seq[User])(
-    implicit apiKey: ApiKeyValue
-  ): Request[Either[ResponseError[Exception], Unit], Nothing] =
+   * Expected answers:
+   *   code 0 :  (successful operation)
+   * 
+   * Available security schemes:
+   *   api_key (apiKey)
+   * 
+   * @param user List of user object
+   */
+  def createUsersWithListInput(user: Seq[User])(implicit apiKey: ApiKeyValue): Request[Either[ResponseError[Exception], Unit], Nothing] =
     basicRequest
       .method(Method.POST, uri"$baseUrl/user/createWithList")
       .contentType("application/json")
@@ -87,20 +73,18 @@ class UserApi(baseUrl: String)(implicit serializer: SttpSerializer) {
       .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:
-    *   api_key (apiKey)
-    *
-    * @param username The name that needs to be deleted
-    */
-  def deleteUser(username: String)(
-    implicit apiKey: ApiKeyValue
-  ): Request[Either[ResponseError[Exception], Unit], Nothing] =
+   * 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:
+   *   api_key (apiKey)
+   * 
+   * @param username The name that needs to be deleted
+   */
+  def deleteUser(username: String)(implicit apiKey: ApiKeyValue): Request[Either[ResponseError[Exception], Unit], Nothing] =
     basicRequest
       .method(Method.DELETE, uri"$baseUrl/user/${username}")
       .contentType("application/json")
@@ -108,55 +92,45 @@ class UserApi(baseUrl: String)(implicit serializer: SttpSerializer) {
       .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
-  ): Request[Either[ResponseError[Exception], User], Nothing] =
+   * 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): Request[Either[ResponseError[Exception], User], Nothing] =
     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 `api_key` 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
-  ): Request[Either[ResponseError[Exception], String], Nothing] =
+   * Expected answers:
+   *   code 200 : String (successful operation)
+   *              Headers :
+   *                Set-Cookie - Cookie authentication key for use with the `api_key` 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): Request[Either[ResponseError[Exception], String], Nothing] =
     basicRequest
-      .method(
-        Method.GET,
-        uri"$baseUrl/user/login?username=$username&password=$password"
-      )
+      .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:
-    *   api_key (apiKey)
-    */
-  def logoutUser()(
-    implicit apiKey: ApiKeyValue
-  ): Request[Either[ResponseError[Exception], Unit], Nothing] =
+   * Expected answers:
+   *   code 0 :  (successful operation)
+   * 
+   * Available security schemes:
+   *   api_key (apiKey)
+   */
+  def logoutUser()(implicit apiKey: ApiKeyValue): Request[Either[ResponseError[Exception], Unit], Nothing] =
     basicRequest
       .method(Method.GET, uri"$baseUrl/user/logout")
       .contentType("application/json")
@@ -164,21 +138,19 @@ class UserApi(baseUrl: String)(implicit serializer: SttpSerializer) {
       .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:
-    *   api_key (apiKey)
-    *
-    * @param username name that need to be deleted
-    * @param user Updated user object
-    */
-  def updateUser(username: String, user: User)(
-    implicit apiKey: ApiKeyValue
-  ): Request[Either[ResponseError[Exception], Unit], Nothing] =
+   * 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:
+   *   api_key (apiKey)
+   * 
+   * @param username name that need to be deleted
+   * @param user Updated user object
+   */
+  def updateUser(username: String, user: User)(implicit apiKey: ApiKeyValue): Request[Either[ResponseError[Exception], Unit], Nothing] =
     basicRequest
       .method(Method.PUT, uri"$baseUrl/user/${username}")
       .contentType("application/json")
@@ -187,3 +159,4 @@ class UserApi(baseUrl: String)(implicit serializer: SttpSerializer) {
       .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
index fb99518cd4e..b6bdab0ea2a 100644
--- 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
@@ -16,9 +16,10 @@ import sttp.client._
 import org.openapitools.client.api.EnumsSerializers
 import sttp.client.json4s.SttpJson4sApi
 
-class SttpSerializer(implicit val format: Formats = DefaultFormats ++ EnumsSerializers.all ++ Serializers.all,
-                     implicit val serialization: org.json4s.Serialization = org.json4s.jackson.Serialization) extends SttpJson4sApi
-
+object JsonSupport extends SttpJson4sApi {
+  implicit val format: Formats = DefaultFormats ++ EnumsSerializers.all ++ Serializers.all
+  implicit val serialization: org.json4s.Serialization = org.json4s.jackson.Serialization
+}
 
 object Helpers {
 
-- 
GitLab


From 3b27bc5610995db1767c3b009677a945440c8b25 Mon Sep 17 00:00:00 2001
From: ghostbuster91 <kghost0@gmail.com>
Date: Thu, 4 Jun 2020 16:32:28 +0200
Subject: [PATCH 09/38] Remove helpers as such functionality was added to sttp

---
 .../src/main/resources/scala-sttp/apiInvoker.mustache | 11 -----------
 1 file changed, 11 deletions(-)

diff --git a/modules/openapi-generator/src/main/resources/scala-sttp/apiInvoker.mustache b/modules/openapi-generator/src/main/resources/scala-sttp/apiInvoker.mustache
index b2487a79b2f..c7a73a7ff91 100644
--- a/modules/openapi-generator/src/main/resources/scala-sttp/apiInvoker.mustache
+++ b/modules/openapi-generator/src/main/resources/scala-sttp/apiInvoker.mustache
@@ -10,14 +10,3 @@ object JsonSupport extends SttpJson4sApi {
   implicit val format: Formats = DefaultFormats ++ EnumsSerializers.all ++ Serializers.all
   implicit val serialization: org.json4s.Serialization = org.json4s.jackson.Serialization
 }
-
-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)
-    }
-  }
-
-}
-- 
GitLab


From cac19fc5f566ecbb527360508941d4230738c452 Mon Sep 17 00:00:00 2001
From: ghostbuster91 <kghost0@gmail.com>
Date: Thu, 4 Jun 2020 16:33:05 +0200
Subject: [PATCH 10/38] Rename file

---
 .../openapitools/codegen/languages/ScalaSttpClientCodegen.java  | 2 +-
 .../scala-sttp/{apiInvoker.mustache => jsonSupport.mustache}    | 0
 2 files changed, 1 insertion(+), 1 deletion(-)
 rename modules/openapi-generator/src/main/resources/scala-sttp/{apiInvoker.mustache => jsonSupport.mustache} (100%)

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
index e7dd8b7dd35..6ee5a5ab371 100644
--- 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
@@ -91,7 +91,7 @@ public class ScalaSttpClientCodegen extends ScalaAkkaClientCodegen implements Co
         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"));
+        supportingFiles.add(new SupportingFile("jsonSupport.mustache", invokerFolder, "JsonSupport.scala"));
         supportingFiles.add(new SupportingFile("project/build.properties.mustache", "project", "build.properties"));
         final String apiFolder = (sourceFolder + File.separator + apiPackage).replace(".", File.separator);
         supportingFiles.add(new SupportingFile("enumsSerializers.mustache", apiFolder, "EnumsSerializers.scala"));
diff --git a/modules/openapi-generator/src/main/resources/scala-sttp/apiInvoker.mustache b/modules/openapi-generator/src/main/resources/scala-sttp/jsonSupport.mustache
similarity index 100%
rename from modules/openapi-generator/src/main/resources/scala-sttp/apiInvoker.mustache
rename to modules/openapi-generator/src/main/resources/scala-sttp/jsonSupport.mustache
-- 
GitLab


From 86ec499e20829087f7b13ab772ed8472ef4dca11 Mon Sep 17 00:00:00 2001
From: ghostbuster91 <kghost0@gmail.com>
Date: Thu, 4 Jun 2020 18:03:35 +0200
Subject: [PATCH 11/38] Fix uploading multipart data

---
 .../src/main/resources/scala-sttp/api.mustache   |  7 +++++--
 .../scala-sttp/paramMultipartCreation.mustache   | 16 ++++++++++++++++
 .../org/openapitools/client/api/PetApi.scala     |  8 +++++++-
 3 files changed, 28 insertions(+), 3 deletions(-)
 create mode 100644 modules/openapi-generator/src/main/resources/scala-sttp/paramMultipartCreation.mustache

diff --git a/modules/openapi-generator/src/main/resources/scala-sttp/api.mustache b/modules/openapi-generator/src/main/resources/scala-sttp/api.mustache
index 2241ae64d2b..530ca4a7167 100644
--- a/modules/openapi-generator/src/main/resources/scala-sttp/api.mustache
+++ b/modules/openapi-generator/src/main/resources/scala-sttp/api.mustache
@@ -24,10 +24,13 @@ class {{classname}}(baseUrl: String = "{{{basePath}}}") {
       .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}}
+      .cookie("{{keyParamName}}", apiKey.value){{/isKeyInCookie}}{{/isApiKey}}{{/authMethods}}{{#formParams.0}}{{^isMultipart}}
       .body(Map({{#formParams}}
         {{>paramFormCreation}}{{#hasMore}}, {{/hasMore}}{{/formParams}}
-      )){{/formParams.0}}{{#bodyParam}}
+      )){{/isMultipart}}{{#isMultipart}}
+      .multipartBody(Seq({{#formParams}}
+        {{>paramMultipartCreation}}{{#hasMore}}, {{/hasMore}}{{/formParams}}
+      ).flatten){{/isMultipart}}{{/formParams.0}}{{#bodyParam}}
       .body({{paramName}}){{/bodyParam}}
       .response({{#separateErrorChannel}}asJson{{/separateErrorChannel}}{{^separateErrorChannel}}asJsonAlwaysUnsafe{{/separateErrorChannel}}[{{>operationReturnType}}])
 
diff --git a/modules/openapi-generator/src/main/resources/scala-sttp/paramMultipartCreation.mustache b/modules/openapi-generator/src/main/resources/scala-sttp/paramMultipartCreation.mustache
new file mode 100644
index 00000000000..edfb7b0766b
--- /dev/null
+++ b/modules/openapi-generator/src/main/resources/scala-sttp/paramMultipartCreation.mustache
@@ -0,0 +1,16 @@
+{{#required}}
+    {{#isFile}}
+        multipartFile("{{baseName}}", {{#isContainer}}ArrayValues({{{paramName}}}{{#collectionFormat}}, {{collectionFormat.toUpperCase}}{{/collectionFormat}}){{/isContainer}}{{^isContainer}}{{{paramName}}}{{/isContainer}})
+    {{/isFile}}
+    {{^isFile}}
+        multipart("{{baseName}}", {{paramName}})
+    {{/isFile}}
+{{/required}}
+{{^required}}
+    {{#isFile}}
+        {{paramName}}.map(multipartFile("{{baseName}}", _))
+    {{/isFile}}
+    {{^isFile}}
+        {{paramName}}.map(multipart("{{baseName}}", {{#isContainer}}ArrayValues(_{{#collectionFormat}}, {{collectionFormat.toUpperCase}}{{/collectionFormat}}){{/isContainer}}{{^isContainer}}_{{/isContainer}}))
+    {{/isFile}}
+{{/required}}
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
index 3420eaf9d60..5d1b6261a4a 100644
--- 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
@@ -51,6 +51,7 @@ class PetApi(baseUrl: String = "http://petstore.swagger.io/v2") {
     basicRequest
       .method(Method.DELETE, uri"$baseUrl/pet/${petId}")
       .contentType("application/json")
+      .header("api_key", apiKey)
       .response(asJson[Unit])
 
   /**
@@ -162,7 +163,12 @@ class PetApi(baseUrl: String = "http://petstore.swagger.io/v2") {
     basicRequest
       .method(Method.POST, uri"$baseUrl/pet/${petId}/uploadImage")
       .contentType("multipart/form-data")
-      .body(Map("additionalMetadata" -> additionalMetadata, "file" -> file))
+      .multipartBody(
+        Seq(
+          additionalMetadata.map(multipart("additionalMetadata", _)),
+          file.map(multipartFile("file", _))
+        ).flatten
+      )
       .response(asJson[ApiResponse])
 
 }
-- 
GitLab


From 97fd17fbf32204db864eccb4050469cd7e4100a7 Mon Sep 17 00:00:00 2001
From: ghostbuster91 <kghost0@gmail.com>
Date: Thu, 4 Jun 2020 18:36:23 +0200
Subject: [PATCH 12/38] Extract common abstraction for generator properties

---
 .../languages/ScalaSttpClientCodegen.java     | 103 ++++++++++++------
 .../main/resources/scala-sttp/api.mustache    |   1 -
 .../scala-sttp/.openapi-generator/FILES       |   2 +-
 .../client/core/JsonSupport.scala             |  22 ++++
 4 files changed, 94 insertions(+), 34 deletions(-)
 create mode 100644 samples/client/petstore/scala-sttp/src/main/scala/org/openapitools/client/core/JsonSupport.scala

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
index 6ee5a5ab371..b65b8088561 100644
--- 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
@@ -26,26 +26,26 @@ import org.openapitools.codegen.meta.GeneratorMetadata;
 import org.openapitools.codegen.meta.Stability;
 
 import java.io.File;
+import java.util.Arrays;
 import java.util.List;
+import java.util.Map;
 
 public class ScalaSttpClientCodegen extends ScalaAkkaClientCodegen implements CodegenConfig {
-    public static final String STTP_CLIENT_VERSION = "sttpClientVersion";
-    public static final String STTP_CLIENT_VERSION_DESC = "The version of sttp client";
-    public static final String STTP_CLIENT_VERSION_DEFAULT = "2.1.5";
-
-    public static final String SEPARATE_ERROR_CHANNEL = "separateErrorChannel";
-    public static final String SEPARATE_ERROR_CHANNEL_DESC = "Whether to return response as " +
-            "F[Either[ResponseError[ErrorType], ReturnType]]] or to flatten " +
-            "response's error raising them through enclosing monad (F[ReturnType]).";
-    public static final Boolean SEPARATE_ERROR_CHANNEL_DEFAULT = true;
-
-    public static final String JODA_TIME_VERSION = "jodaTimeVersion";
-    public static final String JODA_TIME_VERSION_DESC = "The version of joda-time library";
-    public static final String JODA_TIME_VERSION_DEFAULT = "2.10.6";
-
-    public static final String JSON4S_VERSION = "json4sVersion";
-    public static final String JSON4S_VERSION_DESC = "The version of json4s library";
-    public static final String JSON4S_VERSION_DEFAULT = "3.6.8";
+    public static final StringProperty STTP_CLIENT_VERSION = new StringProperty("sttpClientVersion", "The version of " +
+            "sttp " +
+                                                                              "client", "2.1.5");
+    public static final BooleanProperty USE_SEPARATE_ERROR_CHANNEL = new BooleanProperty("separateErrorChannel",
+            "Whether to " +
+                    "return response as " +
+                    "F[Either[ResponseError[ErrorType], ReturnType]]] or to flatten " +
+                    "response's error raising them through enclosing monad (F[ReturnType]).", true);
+    public static final StringProperty JODA_TIME_VERSION = new StringProperty("jodaTimeVersion","The version of " +
+            "joda-time library","2.10.6");
+    public static final StringProperty JSON4S_VERSION = new StringProperty("json4sVersion", "The version of json4s " +
+            "library", "3.6.8");
+
+    public static final List<Property> properties = Arrays.asList(STTP_CLIENT_VERSION, USE_SEPARATE_ERROR_CHANNEL,
+            JODA_TIME_VERSION, JSON4S_VERSION);
 
     public ScalaSttpClientCodegen() {
         super();
@@ -56,10 +56,7 @@ public class ScalaSttpClientCodegen extends ScalaAkkaClientCodegen implements Co
         embeddedTemplateDir = templateDir = "scala-sttp";
         outputFolder = "generated-code/scala-sttp";
 
-        cliOptions.add(CliOption.newString(STTP_CLIENT_VERSION, STTP_CLIENT_VERSION_DESC).defaultValue(STTP_CLIENT_VERSION_DEFAULT));
-        cliOptions.add(CliOption.newString(JODA_TIME_VERSION, JODA_TIME_VERSION_DESC).defaultValue(JODA_TIME_VERSION_DEFAULT));
-        cliOptions.add(CliOption.newString(JSON4S_VERSION, JSON4S_VERSION_DESC).defaultValue(JSON4S_VERSION_DEFAULT));
-        cliOptions.add(CliOption.newBoolean(SEPARATE_ERROR_CHANNEL, SEPARATE_ERROR_CHANNEL_DESC, SEPARATE_ERROR_CHANNEL_DEFAULT));
+        properties.forEach(p->cliOptions.add(p.toCliOption()));
     }
 
     @Override
@@ -74,17 +71,7 @@ public class ScalaSttpClientCodegen extends ScalaAkkaClientCodegen implements Co
             additionalProperties.put("apiPackage", apiPackage);
             additionalProperties.put("modelPackage", modelPackage);
         }
-        if(!additionalProperties.containsKey(STTP_CLIENT_VERSION)) {
-            additionalProperties.put(STTP_CLIENT_VERSION, STTP_CLIENT_VERSION_DEFAULT);
-        }
-        if(!additionalProperties.containsKey(JODA_TIME_VERSION)) {
-            additionalProperties.put(JODA_TIME_VERSION, JODA_TIME_VERSION_DEFAULT);
-        }
-        if(!additionalProperties.containsKey(JSON4S_VERSION)) {
-            additionalProperties.put(JSON4S_VERSION, JSON4S_VERSION_DEFAULT);
-        }
-        Object separateErrorChannel = additionalProperties.getOrDefault(SEPARATE_ERROR_CHANNEL, SEPARATE_ERROR_CHANNEL_DEFAULT);
-        additionalProperties.put(SEPARATE_ERROR_CHANNEL, Boolean.valueOf(separateErrorChannel.toString()));
+        properties.forEach(p-> p.updateAdditionalProperties(additionalProperties));
 
         supportingFiles.clear();
         supportingFiles.add(new SupportingFile("README.mustache", "", "README.md"));
@@ -123,4 +110,56 @@ public class ScalaSttpClientCodegen extends ScalaAkkaClientCodegen implements Co
         op.path = encodePath(path);
         return op;
     }
+
+    public static abstract class Property<T> {
+        final String name;
+        final String description;
+        final T defaultValue;
+
+        private Property(String name, String description, T defaultValue) {
+            this.name = name;
+            this.description = description;
+            this.defaultValue = defaultValue;
+        }
+
+        public abstract CliOption toCliOption();
+
+        public abstract void updateAdditionalProperties(Map<String, Object> additionalProperties);
+    }
+
+    public static class StringProperty extends Property<String> {
+        private StringProperty(String name, String description, String defaultValue) {
+            super(name, description, defaultValue);
+        }
+
+        @Override
+        public CliOption toCliOption() {
+            return CliOption.newString(name, description).defaultValue(defaultValue);
+        }
+
+        @Override
+        public void updateAdditionalProperties(Map<String, Object> additionalProperties) {
+            if(!additionalProperties.containsKey(name)) {
+                additionalProperties.put(name, defaultValue);
+            }
+        }
+    }
+
+    public static class BooleanProperty extends Property<Boolean> {
+        private BooleanProperty(String name, String description, Boolean defaultValue) {
+            super(name, description, defaultValue);
+        }
+
+        @Override
+        public CliOption toCliOption() {
+            return CliOption.newBoolean(name, description, defaultValue);
+        }
+
+        @Override
+        public void updateAdditionalProperties(Map<String, Object> additionalProperties) {
+            String stringedBoolean = additionalProperties.getOrDefault(name, defaultValue.toString()).toString();
+            additionalProperties.put(name, Boolean.valueOf(stringedBoolean));
+        }
+    }
+
 }
diff --git a/modules/openapi-generator/src/main/resources/scala-sttp/api.mustache b/modules/openapi-generator/src/main/resources/scala-sttp/api.mustache
index 530ca4a7167..6aa459ac179 100644
--- a/modules/openapi-generator/src/main/resources/scala-sttp/api.mustache
+++ b/modules/openapi-generator/src/main/resources/scala-sttp/api.mustache
@@ -36,5 +36,4 @@ class {{classname}}(baseUrl: String = "{{{basePath}}}") {
 
 {{/operation}}
 }
-
 {{/operations}}
diff --git a/samples/client/petstore/scala-sttp/.openapi-generator/FILES b/samples/client/petstore/scala-sttp/.openapi-generator/FILES
index ca35c1f7197..990ec3076fa 100644
--- a/samples/client/petstore/scala-sttp/.openapi-generator/FILES
+++ b/samples/client/petstore/scala-sttp/.openapi-generator/FILES
@@ -5,7 +5,7 @@ src/main/scala/org/openapitools/client/api/EnumsSerializers.scala
 src/main/scala/org/openapitools/client/api/PetApi.scala
 src/main/scala/org/openapitools/client/api/StoreApi.scala
 src/main/scala/org/openapitools/client/api/UserApi.scala
-src/main/scala/org/openapitools/client/core/ApiInvoker.scala
+src/main/scala/org/openapitools/client/core/JsonSupport.scala
 src/main/scala/org/openapitools/client/core/Serializers.scala
 src/main/scala/org/openapitools/client/core/requests.scala
 src/main/scala/org/openapitools/client/model/ApiResponse.scala
diff --git a/samples/client/petstore/scala-sttp/src/main/scala/org/openapitools/client/core/JsonSupport.scala b/samples/client/petstore/scala-sttp/src/main/scala/org/openapitools/client/core/JsonSupport.scala
new file mode 100644
index 00000000000..f4df8835093
--- /dev/null
+++ b/samples/client/petstore/scala-sttp/src/main/scala/org/openapitools/client/core/JsonSupport.scala
@@ -0,0 +1,22 @@
+/**
+ * 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 org.openapitools.client.api.EnumsSerializers
+import sttp.client.json4s.SttpJson4sApi
+
+object JsonSupport extends SttpJson4sApi {
+  implicit val format: Formats = DefaultFormats ++ EnumsSerializers.all ++ Serializers.all
+  implicit val serialization: org.json4s.Serialization = org.json4s.jackson.Serialization
+}
-- 
GitLab


From a7a15a2c987daed38d75b7ee8ebdb98318d418fb Mon Sep 17 00:00:00 2001
From: ghostbuster91 <kghost0@gmail.com>
Date: Thu, 4 Jun 2020 19:59:28 +0200
Subject: [PATCH 13/38] Add partial circe support

---
 .../languages/ScalaSttpClientCodegen.java     |  83 ++++++--
 .../resources/scala-sttp/build.sbt.mustache   |  10 +-
 .../scala-sttp/enumsSerializers.mustache      |  42 ----
 .../resources/scala-sttp/jsonSupport.mustache |  48 ++++-
 .../scala-sttp/.openapi-generator/FILES       |   1 -
 .../client/api/EnumsSerializers.scala         |  51 -----
 .../org/openapitools/client/api/PetApi.scala  | 198 ++++++++----------
 .../openapitools/client/api/StoreApi.scala    |   1 -
 .../org/openapitools/client/api/UserApi.scala |   1 -
 .../openapitools/client/core/ApiInvoker.scala |  33 ---
 .../client/core/JsonSupport.scala             |  32 ++-
 11 files changed, 243 insertions(+), 257 deletions(-)
 delete mode 100644 modules/openapi-generator/src/main/resources/scala-sttp/enumsSerializers.mustache
 delete mode 100644 samples/client/petstore/scala-sttp/src/main/scala/org/openapitools/client/api/EnumsSerializers.scala
 delete mode 100644 samples/client/petstore/scala-sttp/src/main/scala/org/openapitools/client/core/ApiInvoker.scala

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
index b65b8088561..73067744402 100644
--- 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
@@ -24,28 +24,40 @@ import org.openapitools.codegen.CodegenOperation;
 import org.openapitools.codegen.SupportingFile;
 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.List;
 import java.util.Map;
+import java.util.Optional;
+import java.util.stream.Collectors;
 
 public class ScalaSttpClientCodegen extends ScalaAkkaClientCodegen implements CodegenConfig {
-    public static final StringProperty STTP_CLIENT_VERSION = new StringProperty("sttpClientVersion", "The version of " +
+    private static final Logger LOGGER = LoggerFactory.getLogger(ScalaSttpClientCodegen.class);
+
+    private static final StringProperty STTP_CLIENT_VERSION = new StringProperty("sttpClientVersion", "The version of " +
             "sttp " +
                                                                               "client", "2.1.5");
-    public static final BooleanProperty USE_SEPARATE_ERROR_CHANNEL = new BooleanProperty("separateErrorChannel",
+    private static final BooleanProperty USE_SEPARATE_ERROR_CHANNEL = new BooleanProperty("separateErrorChannel",
             "Whether to " +
                     "return response as " +
                     "F[Either[ResponseError[ErrorType], ReturnType]]] or to flatten " +
                     "response's error raising them through enclosing monad (F[ReturnType]).", true);
-    public static final StringProperty JODA_TIME_VERSION = new StringProperty("jodaTimeVersion","The version of " +
+    private static final StringProperty JODA_TIME_VERSION = new StringProperty("jodaTimeVersion","The version of " +
             "joda-time library","2.10.6");
-    public static final StringProperty JSON4S_VERSION = new StringProperty("json4sVersion", "The version of json4s " +
+    private static final StringProperty JSON4S_VERSION = new StringProperty("json4sVersion", "The version of json4s " +
             "library", "3.6.8");
+    private static final BooleanProperty USE_JSON4S = new BooleanProperty("useJson4s", "Whether to use json4s library " +
+            "for json serialization", true);
+    private static final BooleanProperty USE_CIRCE = new BooleanProperty("useCirce", "Whether to use circe library " +
+            "for json serialization", false);
+    private static final StringProperty CIRCE_VERSION = new StringProperty("circeVersion", "The version of circe " +
+            "library", "0.13.0");
 
-    public static final List<Property> properties = Arrays.asList(STTP_CLIENT_VERSION, USE_SEPARATE_ERROR_CHANNEL,
-            JODA_TIME_VERSION, JSON4S_VERSION);
+    private static final List<Property> properties = Arrays.asList(STTP_CLIENT_VERSION, USE_SEPARATE_ERROR_CHANNEL,
+            JODA_TIME_VERSION, JSON4S_VERSION, USE_JSON4S, USE_CIRCE, CIRCE_VERSION);
 
     public ScalaSttpClientCodegen() {
         super();
@@ -71,6 +83,7 @@ public class ScalaSttpClientCodegen extends ScalaAkkaClientCodegen implements Co
             additionalProperties.put("apiPackage", apiPackage);
             additionalProperties.put("modelPackage", modelPackage);
         }
+        checkJsonLibraryConflict(additionalProperties);
         properties.forEach(p-> p.updateAdditionalProperties(additionalProperties));
 
         supportingFiles.clear();
@@ -80,8 +93,6 @@ public class ScalaSttpClientCodegen extends ScalaAkkaClientCodegen implements Co
         supportingFiles.add(new SupportingFile("requests.mustache", invokerFolder, "requests.scala"));
         supportingFiles.add(new SupportingFile("jsonSupport.mustache", invokerFolder, "JsonSupport.scala"));
         supportingFiles.add(new SupportingFile("project/build.properties.mustache", "project", "build.properties"));
-        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"));
     }
 
@@ -111,7 +122,25 @@ public class ScalaSttpClientCodegen extends ScalaAkkaClientCodegen implements Co
         return op;
     }
 
-    public static abstract class Property<T> {
+    private static  void checkJsonLibraryConflict(Map<String, Object> additionalProperties) {
+        int optionCount = 0;
+        if(USE_CIRCE.getValue(additionalProperties)){
+            optionCount++;
+            USE_JSON4S.setValue(additionalProperties, false);
+        }
+        if(USE_JSON4S.getValue(additionalProperties)){
+            optionCount++;
+            USE_CIRCE.setValue(additionalProperties, false);
+        }
+        if(optionCount > 1) {
+            LOGGER.warn("Multiple json libraries specified, default one will be used.");
+        }
+        if(optionCount < 1) {
+            LOGGER.warn("No json library specified. Please choose one.");
+        }
+    }
+
+    private static abstract class Property<T> {
         final String name;
         final String description;
         final T defaultValue;
@@ -125,9 +154,17 @@ public class ScalaSttpClientCodegen extends ScalaAkkaClientCodegen implements Co
         public abstract CliOption toCliOption();
 
         public abstract void updateAdditionalProperties(Map<String, Object> additionalProperties);
+
+        public abstract T getValue(Map<String,Object> additionalProperties);
+
+        public abstract Optional<T> getUserValue(Map<String,Object> additionalProperties);
+
+        public void setValue(Map<String,Object> additionalProperties, T value ) {
+            additionalProperties.put(name, value);
+        }
     }
 
-    public static class StringProperty extends Property<String> {
+    private static class StringProperty extends Property<String> {
         private StringProperty(String name, String description, String defaultValue) {
             super(name, description, defaultValue);
         }
@@ -143,9 +180,19 @@ public class ScalaSttpClientCodegen extends ScalaAkkaClientCodegen implements Co
                 additionalProperties.put(name, defaultValue);
             }
         }
+
+        @Override
+        public String getValue(Map<String, Object> additionalProperties) {
+            return additionalProperties.getOrDefault(name,defaultValue).toString();
+        }
+
+        @Override
+        public Optional<String> getUserValue(Map<String, Object> additionalProperties) {
+            return Optional.ofNullable(additionalProperties.get(name)).map(Object::toString);
+        }
     }
 
-    public static class BooleanProperty extends Property<Boolean> {
+    private static class BooleanProperty extends Property<Boolean> {
         private BooleanProperty(String name, String description, Boolean defaultValue) {
             super(name, description, defaultValue);
         }
@@ -157,8 +204,18 @@ public class ScalaSttpClientCodegen extends ScalaAkkaClientCodegen implements Co
 
         @Override
         public void updateAdditionalProperties(Map<String, Object> additionalProperties) {
-            String stringedBoolean = additionalProperties.getOrDefault(name, defaultValue.toString()).toString();
-            additionalProperties.put(name, Boolean.valueOf(stringedBoolean));
+            Boolean value = getValue(additionalProperties);
+            additionalProperties.put(name, value);
+        }
+
+        @Override
+        public Boolean getValue(Map<String, Object> additionalProperties) {
+            return Boolean.valueOf(additionalProperties.getOrDefault(name, defaultValue.toString()).toString());
+        }
+
+        @Override
+        public Optional<Boolean> getUserValue(Map<String, Object> additionalProperties) {
+            return Optional.ofNullable(additionalProperties.get(name)).map(v -> Boolean.valueOf(v.toString()));
         }
     }
 
diff --git a/modules/openapi-generator/src/main/resources/scala-sttp/build.sbt.mustache b/modules/openapi-generator/src/main/resources/scala-sttp/build.sbt.mustache
index 13c0e513433..218a44a86e8 100644
--- a/modules/openapi-generator/src/main/resources/scala-sttp/build.sbt.mustache
+++ b/modules/openapi-generator/src/main/resources/scala-sttp/build.sbt.mustache
@@ -8,11 +8,19 @@ crossScalaVersions := Seq(scalaVersion.value, "2.12.10", "2.11.12")
 
 libraryDependencies ++= Seq(
   "com.softwaremill.sttp.client" %% "core" % "{{sttpClientVersion}}",
-  "com.softwaremill.sttp.client" %% "json4s" % "{{sttpClientVersion}}",
 {{#joda}}
   "joda-time" % "joda-time" % "{{jodaTimeVersion}}",
 {{/joda}}
+{{#useJson4s}}
+  "com.softwaremill.sttp.client" %% "json4s" % "{{sttpClientVersion}}",
   "org.json4s" %% "json4s-jackson" % "{{json4sVersion}}"
+{{/useJson4s}}
+{{#useCirce}}
+  "com.softwaremill.sttp.client" %% "circe" % "{{sttpClientVersion}}",
+  "io.circe" %% "circe-core" % "{{circeVersion}}",
+  "io.circe" %% "circe-generic" % "{{circeVersion}}",
+  "io.circe" %% "circe-parser" % "{{circeVersion}}"
+{{/useCirce}}
 )
 
 scalacOptions := Seq(
diff --git a/modules/openapi-generator/src/main/resources/scala-sttp/enumsSerializers.mustache b/modules/openapi-generator/src/main/resources/scala-sttp/enumsSerializers.mustache
deleted file mode 100644
index 8c7e6f2e41e..00000000000
--- a/modules/openapi-generator/src/main/resources/scala-sttp/enumsSerializers.mustache
+++ /dev/null
@@ -1,42 +0,0 @@
-{{>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/jsonSupport.mustache b/modules/openapi-generator/src/main/resources/scala-sttp/jsonSupport.mustache
index c7a73a7ff91..9c1a9b2be33 100644
--- a/modules/openapi-generator/src/main/resources/scala-sttp/jsonSupport.mustache
+++ b/modules/openapi-generator/src/main/resources/scala-sttp/jsonSupport.mustache
@@ -1,12 +1,54 @@
 {{>licenseInfo}}
 package {{invokerPackage}}
 
+{{#models.0}}
+import {{modelPackage}}._
+{{/models.0}}
+{{#useJson4s}}
 import org.json4s._
-import sttp.client._
-import {{{apiPackage}}}.EnumsSerializers
 import sttp.client.json4s.SttpJson4sApi
+import scala.reflect.ClassTag
 
 object JsonSupport extends SttpJson4sApi {
-  implicit val format: Formats = DefaultFormats ++ EnumsSerializers.all ++ Serializers.all
+  def enumSerializers: 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
+      }
+    }
+
+  implicit val format: Formats = DefaultFormats ++ enumSerializers ++ Serializers.all
   implicit val serialization: org.json4s.Serialization = org.json4s.jackson.Serialization
 }
+{{/useJson4s}}
+{{#useCirce}}
+import io.circe.{Decoder, Encoder}
+import io.circe.generic.AutoDerivation
+import sttp.client.circe.SttpCirceApi
+
+object JsonSupport extends SttpCirceApi with AutoDerivation {
+
+{{#models}}{{#model}}{{#hasEnums}}{{#vars}}{{#isEnum}}
+  implicit val {{classname}}{{datatypeWithEnum}}Decoder: Decoder[{{classname}}Enums.{{datatypeWithEnum}}] = Decoder.decodeEnumeration({{classname}}Enums.{{datatypeWithEnum}})
+  implicit val {{classname}}{{datatypeWithEnum}}Encoder: Encoder[{{classname}}Enums.{{datatypeWithEnum}}] = Encoder.encodeEnumeration({{classname}}Enums.{{datatypeWithEnum}})
+{{/isEnum}}{{/vars}}{{/hasEnums}}{{/model}}{{/models}}
+}
+{{/useCirce}}
diff --git a/samples/client/petstore/scala-sttp/.openapi-generator/FILES b/samples/client/petstore/scala-sttp/.openapi-generator/FILES
index 990ec3076fa..28999b7bc31 100644
--- a/samples/client/petstore/scala-sttp/.openapi-generator/FILES
+++ b/samples/client/petstore/scala-sttp/.openapi-generator/FILES
@@ -1,7 +1,6 @@
 README.md
 build.sbt
 project/build.properties
-src/main/scala/org/openapitools/client/api/EnumsSerializers.scala
 src/main/scala/org/openapitools/client/api/PetApi.scala
 src/main/scala/org/openapitools/client/api/StoreApi.scala
 src/main/scala/org/openapitools/client/api/UserApi.scala
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
deleted file mode 100644
index 71ad618e31f..00000000000
--- a/samples/client/petstore/scala-sttp/src/main/scala/org/openapitools/client/api/EnumsSerializers.scala
+++ /dev/null
@@ -1,51 +0,0 @@
-/**
- * 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
index 5d1b6261a4a..8e9be2c3795 100644
--- 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
@@ -1,14 +1,14 @@
 /**
-  * 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.
-  */
+ * 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
@@ -22,15 +22,13 @@ import sttp.model.Method
 class PetApi(baseUrl: String = "http://petstore.swagger.io/v2") {
 
   /**
-    * 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
-  ): Request[Either[ResponseError[Exception], Pet], Nothing] =
+   * 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): Request[Either[ResponseError[Exception], Pet], Nothing] =
     basicRequest
       .method(Method.POST, uri"$baseUrl/pet")
       .contentType("application/json")
@@ -38,16 +36,13 @@ class PetApi(baseUrl: String = "http://petstore.swagger.io/v2") {
       .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
-  ): Request[Either[ResponseError[Exception], Unit], Nothing] =
+   * Expected answers:
+   *   code 400 :  (Invalid pet value)
+   * 
+   * @param petId Pet id to delete
+   * @param apiKey 
+   */
+  def deletePet(petId: Long, apiKey: Option[String] = None): Request[Either[ResponseError[Exception], Unit], Nothing] =
     basicRequest
       .method(Method.DELETE, uri"$baseUrl/pet/${petId}")
       .contentType("application/json")
@@ -55,55 +50,49 @@ class PetApi(baseUrl: String = "http://petstore.swagger.io/v2") {
       .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]
-  ): Request[Either[ResponseError[Exception], Seq[Pet]], Nothing] =
+   * 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]): Request[Either[ResponseError[Exception], Seq[Pet]], Nothing] =
     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]
-  ): Request[Either[ResponseError[Exception], Seq[Pet]], Nothing] =
+   * 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]): Request[Either[ResponseError[Exception], Seq[Pet]], Nothing] =
     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
-  ): Request[Either[ResponseError[Exception], Pet], Nothing] =
+   * 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): Request[Either[ResponseError[Exception], Pet], Nothing] =
     basicRequest
       .method(Method.GET, uri"$baseUrl/pet/${petId}")
       .contentType("application/json")
@@ -111,17 +100,15 @@ class PetApi(baseUrl: String = "http://petstore.swagger.io/v2") {
       .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
-  ): Request[Either[ResponseError[Exception], Pet], Nothing] =
+   * 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): Request[Either[ResponseError[Exception], Pet], Nothing] =
     basicRequest
       .method(Method.PUT, uri"$baseUrl/pet")
       .contentType("application/json")
@@ -129,46 +116,41 @@ class PetApi(baseUrl: String = "http://petstore.swagger.io/v2") {
       .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
-  ): Request[Either[ResponseError[Exception], Unit], Nothing] =
+   * 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): Request[Either[ResponseError[Exception], Unit], Nothing] =
     basicRequest
       .method(Method.POST, uri"$baseUrl/pet/${petId}")
       .contentType("application/x-www-form-urlencoded")
-      .body(Map("name" -> name, "status" -> status))
+      .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
-  ): Request[Either[ResponseError[Exception], ApiResponse], Nothing] =
+   * 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): Request[Either[ResponseError[Exception], ApiResponse], Nothing] =
     basicRequest
       .method(Method.POST, uri"$baseUrl/pet/${petId}/uploadImage")
       .contentType("multipart/form-data")
-      .multipartBody(
-        Seq(
-          additionalMetadata.map(multipart("additionalMetadata", _)),
-          file.map(multipartFile("file", _))
-        ).flatten
-      )
+      .multipartBody(Seq(
+                additionalMetadata.map(multipart("additionalMetadata", _))
+, 
+                file.map(multipartFile("file", _))
+
+      ).flatten)
       .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
index 8d78087626a..7ddba54d894 100644
--- 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
@@ -81,4 +81,3 @@ class StoreApi(baseUrl: String = "http://petstore.swagger.io/v2") {
       .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
index b57cf699ad7..058925130cc 100644
--- 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
@@ -159,4 +159,3 @@ class UserApi(baseUrl: String = "http://petstore.swagger.io/v2") {
       .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
deleted file mode 100644
index b6bdab0ea2a..00000000000
--- a/samples/client/petstore/scala-sttp/src/main/scala/org/openapitools/client/core/ApiInvoker.scala
+++ /dev/null
@@ -1,33 +0,0 @@
-/**
- * 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 org.openapitools.client.api.EnumsSerializers
-import sttp.client.json4s.SttpJson4sApi
-
-object JsonSupport extends SttpJson4sApi {
-  implicit val format: Formats = DefaultFormats ++ EnumsSerializers.all ++ Serializers.all
-  implicit val serialization: org.json4s.Serialization = org.json4s.jackson.Serialization
-}
-
-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)
-    }
-  }
-
-}
diff --git a/samples/client/petstore/scala-sttp/src/main/scala/org/openapitools/client/core/JsonSupport.scala b/samples/client/petstore/scala-sttp/src/main/scala/org/openapitools/client/core/JsonSupport.scala
index f4df8835093..33d158b6fd1 100644
--- a/samples/client/petstore/scala-sttp/src/main/scala/org/openapitools/client/core/JsonSupport.scala
+++ b/samples/client/petstore/scala-sttp/src/main/scala/org/openapitools/client/core/JsonSupport.scala
@@ -11,12 +11,38 @@
  */
 package org.openapitools.client.core
 
+import org.openapitools.client.model._
 import org.json4s._
-import sttp.client._
-import org.openapitools.client.api.EnumsSerializers
 import sttp.client.json4s.SttpJson4sApi
+import scala.reflect.ClassTag
 
 object JsonSupport extends SttpJson4sApi {
-  implicit val format: Formats = DefaultFormats ++ EnumsSerializers.all ++ Serializers.all
+  def enumSerializers: 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
+      }
+    }
+
+  implicit val format: Formats = DefaultFormats ++ enumSerializers ++ Serializers.all
   implicit val serialization: org.json4s.Serialization = org.json4s.jackson.Serialization
 }
-- 
GitLab


From 551bb35b7acf1c899878505d51c6baeec8e7ca85 Mon Sep 17 00:00:00 2001
From: ghostbuster91 <kghost0@gmail.com>
Date: Thu, 4 Jun 2020 20:00:31 +0200
Subject: [PATCH 14/38] Remove unsed method

---
 .../codegen/languages/ScalaSttpClientCodegen.java    | 12 ------------
 1 file changed, 12 deletions(-)

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
index 73067744402..b08a7b2cc8b 100644
--- 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
@@ -157,8 +157,6 @@ public class ScalaSttpClientCodegen extends ScalaAkkaClientCodegen implements Co
 
         public abstract T getValue(Map<String,Object> additionalProperties);
 
-        public abstract Optional<T> getUserValue(Map<String,Object> additionalProperties);
-
         public void setValue(Map<String,Object> additionalProperties, T value ) {
             additionalProperties.put(name, value);
         }
@@ -185,11 +183,6 @@ public class ScalaSttpClientCodegen extends ScalaAkkaClientCodegen implements Co
         public String getValue(Map<String, Object> additionalProperties) {
             return additionalProperties.getOrDefault(name,defaultValue).toString();
         }
-
-        @Override
-        public Optional<String> getUserValue(Map<String, Object> additionalProperties) {
-            return Optional.ofNullable(additionalProperties.get(name)).map(Object::toString);
-        }
     }
 
     private static class BooleanProperty extends Property<Boolean> {
@@ -212,11 +205,6 @@ public class ScalaSttpClientCodegen extends ScalaAkkaClientCodegen implements Co
         public Boolean getValue(Map<String, Object> additionalProperties) {
             return Boolean.valueOf(additionalProperties.getOrDefault(name, defaultValue.toString()).toString());
         }
-
-        @Override
-        public Optional<Boolean> getUserValue(Map<String, Object> additionalProperties) {
-            return Optional.ofNullable(additionalProperties.get(name)).map(v -> Boolean.valueOf(v.toString()));
-        }
     }
 
 }
-- 
GitLab


From 2a91b11e68079bf303a695daff43b6482ac3c89d Mon Sep 17 00:00:00 2001
From: ghostbuster91 <kghost0@gmail.com>
Date: Thu, 4 Jun 2020 20:37:19 +0200
Subject: [PATCH 15/38] Refactor picking up json library

---
 .../languages/ScalaSttpClientCodegen.java     | 54 +++++++++----------
 1 file changed, 27 insertions(+), 27 deletions(-)

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
index b08a7b2cc8b..b9b19116528 100644
--- 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
@@ -31,8 +31,6 @@ import java.io.File;
 import java.util.Arrays;
 import java.util.List;
 import java.util.Map;
-import java.util.Optional;
-import java.util.stream.Collectors;
 
 public class ScalaSttpClientCodegen extends ScalaAkkaClientCodegen implements CodegenConfig {
     private static final Logger LOGGER = LoggerFactory.getLogger(ScalaSttpClientCodegen.class);
@@ -49,15 +47,12 @@ public class ScalaSttpClientCodegen extends ScalaAkkaClientCodegen implements Co
             "joda-time library","2.10.6");
     private static final StringProperty JSON4S_VERSION = new StringProperty("json4sVersion", "The version of json4s " +
             "library", "3.6.8");
-    private static final BooleanProperty USE_JSON4S = new BooleanProperty("useJson4s", "Whether to use json4s library " +
-            "for json serialization", true);
-    private static final BooleanProperty USE_CIRCE = new BooleanProperty("useCirce", "Whether to use circe library " +
-            "for json serialization", false);
     private static final StringProperty CIRCE_VERSION = new StringProperty("circeVersion", "The version of circe " +
             "library", "0.13.0");
+    private static final JsonLibraryProperty JSON_LIBRARY_PROPERTY = new JsonLibraryProperty();
 
     private static final List<Property> properties = Arrays.asList(STTP_CLIENT_VERSION, USE_SEPARATE_ERROR_CHANNEL,
-            JODA_TIME_VERSION, JSON4S_VERSION, USE_JSON4S, USE_CIRCE, CIRCE_VERSION);
+            JODA_TIME_VERSION, JSON4S_VERSION, CIRCE_VERSION, JSON_LIBRARY_PROPERTY);
 
     public ScalaSttpClientCodegen() {
         super();
@@ -68,7 +63,7 @@ public class ScalaSttpClientCodegen extends ScalaAkkaClientCodegen implements Co
         embeddedTemplateDir = templateDir = "scala-sttp";
         outputFolder = "generated-code/scala-sttp";
 
-        properties.forEach(p->cliOptions.add(p.toCliOption()));
+        properties.forEach(p-> cliOptions.add(p.toCliOption()));
     }
 
     @Override
@@ -83,7 +78,6 @@ public class ScalaSttpClientCodegen extends ScalaAkkaClientCodegen implements Co
             additionalProperties.put("apiPackage", apiPackage);
             additionalProperties.put("modelPackage", modelPackage);
         }
-        checkJsonLibraryConflict(additionalProperties);
         properties.forEach(p-> p.updateAdditionalProperties(additionalProperties));
 
         supportingFiles.clear();
@@ -122,24 +116,6 @@ public class ScalaSttpClientCodegen extends ScalaAkkaClientCodegen implements Co
         return op;
     }
 
-    private static  void checkJsonLibraryConflict(Map<String, Object> additionalProperties) {
-        int optionCount = 0;
-        if(USE_CIRCE.getValue(additionalProperties)){
-            optionCount++;
-            USE_JSON4S.setValue(additionalProperties, false);
-        }
-        if(USE_JSON4S.getValue(additionalProperties)){
-            optionCount++;
-            USE_CIRCE.setValue(additionalProperties, false);
-        }
-        if(optionCount > 1) {
-            LOGGER.warn("Multiple json libraries specified, default one will be used.");
-        }
-        if(optionCount < 1) {
-            LOGGER.warn("No json library specified. Please choose one.");
-        }
-    }
-
     private static abstract class Property<T> {
         final String name;
         final String description;
@@ -207,4 +183,28 @@ public class ScalaSttpClientCodegen extends ScalaAkkaClientCodegen implements Co
         }
     }
 
+    private static class JsonLibraryProperty extends StringProperty {
+        private static final String JSON4S = "json4s";
+        private static final String CIRCE = "circe";
+        private static final String USE_CIRCE_PROPERTY = "useCirce";
+        private static final String USE_JSON4S_PROPERTY = "useJson4s";
+
+        private JsonLibraryProperty() {
+            super("jsonLibrary", "Json library to use. Possible values are: json4s and circe.", JSON4S);
+        }
+
+        @Override
+        public void updateAdditionalProperties(Map<String, Object> additionalProperties) {
+            String value = getValue(additionalProperties);
+            if (value.equals(CIRCE) || value.equals(JSON4S)) {
+                additionalProperties.put(USE_CIRCE_PROPERTY, value.equals(CIRCE));
+                additionalProperties.put(USE_JSON4S_PROPERTY, value.equals(JSON4S));
+            } else {
+                IllegalArgumentException exception = new IllegalArgumentException("Unsupported json library: " + value);
+                LOGGER.error("Unsupported json library " + value, exception);
+                throw exception;
+            }
+        }
+    }
+
 }
-- 
GitLab


From a3805310f3475cdfe1a73bd8e535abb141cdd4d0 Mon Sep 17 00:00:00 2001
From: ghostbuster91 <kghost0@gmail.com>
Date: Tue, 9 Jun 2020 11:45:26 +0200
Subject: [PATCH 16/38] Add missing DateSerializers for circe

---
 .../languages/ScalaSttpClientCodegen.java     |  6 +-
 .../resources/scala-sttp/build.sbt.mustache   |  8 +-
 .../scala-sttp/dateSerializers.mustache       | 76 +++++++++++++++++++
 .../resources/scala-sttp/jsonSupport.mustache | 13 ++--
 .../resources/scala-sttp/serializers.mustache | 57 --------------
 .../scala-sttp/.openapi-generator/FILES       |  2 +-
 .../client/core/DateSerializers.scala         | 29 +++++++
 .../client/core/JsonSupport.scala             |  2 +-
 .../client/core/Serializers.scala             | 31 --------
 9 files changed, 120 insertions(+), 104 deletions(-)
 create mode 100644 modules/openapi-generator/src/main/resources/scala-sttp/dateSerializers.mustache
 delete mode 100644 modules/openapi-generator/src/main/resources/scala-sttp/serializers.mustache
 create mode 100644 samples/client/petstore/scala-sttp/src/main/scala/org/openapitools/client/core/DateSerializers.scala
 delete mode 100644 samples/client/petstore/scala-sttp/src/main/scala/org/openapitools/client/core/Serializers.scala

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
index b9b19116528..4231b567bc2 100644
--- 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
@@ -87,7 +87,7 @@ public class ScalaSttpClientCodegen extends ScalaAkkaClientCodegen implements Co
         supportingFiles.add(new SupportingFile("requests.mustache", invokerFolder, "requests.scala"));
         supportingFiles.add(new SupportingFile("jsonSupport.mustache", invokerFolder, "JsonSupport.scala"));
         supportingFiles.add(new SupportingFile("project/build.properties.mustache", "project", "build.properties"));
-        supportingFiles.add(new SupportingFile("serializers.mustache", invokerFolder, "Serializers.scala"));
+        supportingFiles.add(new SupportingFile("dateSerializers.mustache", invokerFolder, "DateSerializers.scala"));
     }
 
     @Override
@@ -186,8 +186,8 @@ public class ScalaSttpClientCodegen extends ScalaAkkaClientCodegen implements Co
     private static class JsonLibraryProperty extends StringProperty {
         private static final String JSON4S = "json4s";
         private static final String CIRCE = "circe";
-        private static final String USE_CIRCE_PROPERTY = "useCirce";
-        private static final String USE_JSON4S_PROPERTY = "useJson4s";
+        private static final String USE_CIRCE_PROPERTY = "circe";
+        private static final String USE_JSON4S_PROPERTY = "json4s";
 
         private JsonLibraryProperty() {
             super("jsonLibrary", "Json library to use. Possible values are: json4s and circe.", JSON4S);
diff --git a/modules/openapi-generator/src/main/resources/scala-sttp/build.sbt.mustache b/modules/openapi-generator/src/main/resources/scala-sttp/build.sbt.mustache
index 218a44a86e8..4fcde1bb28c 100644
--- a/modules/openapi-generator/src/main/resources/scala-sttp/build.sbt.mustache
+++ b/modules/openapi-generator/src/main/resources/scala-sttp/build.sbt.mustache
@@ -11,16 +11,16 @@ libraryDependencies ++= Seq(
 {{#joda}}
   "joda-time" % "joda-time" % "{{jodaTimeVersion}}",
 {{/joda}}
-{{#useJson4s}}
+{{#json4s}}
   "com.softwaremill.sttp.client" %% "json4s" % "{{sttpClientVersion}}",
   "org.json4s" %% "json4s-jackson" % "{{json4sVersion}}"
-{{/useJson4s}}
-{{#useCirce}}
+{{/json4s}}
+{{#circe}}
   "com.softwaremill.sttp.client" %% "circe" % "{{sttpClientVersion}}",
   "io.circe" %% "circe-core" % "{{circeVersion}}",
   "io.circe" %% "circe-generic" % "{{circeVersion}}",
   "io.circe" %% "circe-parser" % "{{circeVersion}}"
-{{/useCirce}}
+{{/circe}}
 )
 
 scalacOptions := Seq(
diff --git a/modules/openapi-generator/src/main/resources/scala-sttp/dateSerializers.mustache b/modules/openapi-generator/src/main/resources/scala-sttp/dateSerializers.mustache
new file mode 100644
index 00000000000..779e7a428de
--- /dev/null
+++ b/modules/openapi-generator/src/main/resources/scala-sttp/dateSerializers.mustache
@@ -0,0 +1,76 @@
+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}}
+
+{{#json4s}}
+object DateSerializers {
+    import org.json4s.{Serializer, CustomSerializer, JNull}
+    import org.json4s.JsonAST.JString
+    {{#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
+}
+{{/json4s}}
+{{#circe}}
+trait DateSerializers {
+    import io.circe.{Decoder, Encoder}
+    {{#java8}}
+    implicit val isoOffsetDateTimeDecoder: Decoder[OffsetDateTime] = Decoder.decodeOffsetDateTimeWithFormatter(DateTimeFormatter.ISO_OFFSET_DATE_TIME)
+    implicit val isoOffsetDateTimeEncoder: Encoder[OffsetDateTime] = Encoder.encodeOffsetDateTimeWithFormatter(DateTimeFormatter.ISO_OFFSET_DATE_TIME)
+
+    implicit val localDateDecoder: Decoder[LocalDate] = Decoder.decodeLocalDateWithFormatter(DateTimeFormatter.ISO_LOCAL_DATE)
+    implicit val localDateEncoder: Encoder[LocalDate] = Encoder.encodeLocalDateWithFormatter(DateTimeFormatter.ISO_LOCAL_DATE)
+    {{/java8}}
+    {{#joda}}
+    implicit val dateTimeDecoder: Decoder[DateTime] = Decoder.decodeString.map(ISODateTimeFormat.dateOptionalTimeParser().parseDateTime(_))
+    implicit val dateTimeEncoder: Encoder[DateTime] = Encoder.encodeString.contramap(ISODateTimeFormat.dateTime().print(_))
+
+    implicit val localDateDecoder: Decoder[org.joda.time.LocalDate] = Decoder.decodeString.map(org.joda.time.format.DateTimeFormat.forPattern("yyyy-MM-dd").parseLocalDate(_))
+    implicit val localDateEncoder: Encoder[org.joda.time.LocalDate] = Encoder.encodeString.contramap(_.toString("yyyy-MM-dd"))
+    {{/joda}}
+}
+{{/circe}}
diff --git a/modules/openapi-generator/src/main/resources/scala-sttp/jsonSupport.mustache b/modules/openapi-generator/src/main/resources/scala-sttp/jsonSupport.mustache
index 9c1a9b2be33..57c3ab4204c 100644
--- a/modules/openapi-generator/src/main/resources/scala-sttp/jsonSupport.mustache
+++ b/modules/openapi-generator/src/main/resources/scala-sttp/jsonSupport.mustache
@@ -4,7 +4,7 @@ package {{invokerPackage}}
 {{#models.0}}
 import {{modelPackage}}._
 {{/models.0}}
-{{#useJson4s}}
+{{#json4s}}
 import org.json4s._
 import sttp.client.json4s.SttpJson4sApi
 import scala.reflect.ClassTag
@@ -35,20 +35,19 @@ object JsonSupport extends SttpJson4sApi {
       }
     }
 
-  implicit val format: Formats = DefaultFormats ++ enumSerializers ++ Serializers.all
+  implicit val format: Formats = DefaultFormats ++ enumSerializers ++ DateSerializers.all
   implicit val serialization: org.json4s.Serialization = org.json4s.jackson.Serialization
 }
-{{/useJson4s}}
-{{#useCirce}}
+{{/json4s}}
+{{#circe}}
 import io.circe.{Decoder, Encoder}
 import io.circe.generic.AutoDerivation
 import sttp.client.circe.SttpCirceApi
 
-object JsonSupport extends SttpCirceApi with AutoDerivation {
-
+object JsonSupport extends SttpCirceApi with AutoDerivation with DateSerializers {
 {{#models}}{{#model}}{{#hasEnums}}{{#vars}}{{#isEnum}}
   implicit val {{classname}}{{datatypeWithEnum}}Decoder: Decoder[{{classname}}Enums.{{datatypeWithEnum}}] = Decoder.decodeEnumeration({{classname}}Enums.{{datatypeWithEnum}})
   implicit val {{classname}}{{datatypeWithEnum}}Encoder: Encoder[{{classname}}Enums.{{datatypeWithEnum}}] = Encoder.encodeEnumeration({{classname}}Enums.{{datatypeWithEnum}})
 {{/isEnum}}{{/vars}}{{/hasEnums}}{{/model}}{{/models}}
 }
-{{/useCirce}}
+{{/circe}}
diff --git a/modules/openapi-generator/src/main/resources/scala-sttp/serializers.mustache b/modules/openapi-generator/src/main/resources/scala-sttp/serializers.mustache
deleted file mode 100644
index a17d7706915..00000000000
--- a/modules/openapi-generator/src/main/resources/scala-sttp/serializers.mustache
+++ /dev/null
@@ -1,57 +0,0 @@
-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/FILES b/samples/client/petstore/scala-sttp/.openapi-generator/FILES
index 28999b7bc31..15444ab9209 100644
--- a/samples/client/petstore/scala-sttp/.openapi-generator/FILES
+++ b/samples/client/petstore/scala-sttp/.openapi-generator/FILES
@@ -4,8 +4,8 @@ project/build.properties
 src/main/scala/org/openapitools/client/api/PetApi.scala
 src/main/scala/org/openapitools/client/api/StoreApi.scala
 src/main/scala/org/openapitools/client/api/UserApi.scala
+src/main/scala/org/openapitools/client/core/DateSerializers.scala
 src/main/scala/org/openapitools/client/core/JsonSupport.scala
-src/main/scala/org/openapitools/client/core/Serializers.scala
 src/main/scala/org/openapitools/client/core/requests.scala
 src/main/scala/org/openapitools/client/model/ApiResponse.scala
 src/main/scala/org/openapitools/client/model/Category.scala
diff --git a/samples/client/petstore/scala-sttp/src/main/scala/org/openapitools/client/core/DateSerializers.scala b/samples/client/petstore/scala-sttp/src/main/scala/org/openapitools/client/core/DateSerializers.scala
new file mode 100644
index 00000000000..cb2d1d2aa43
--- /dev/null
+++ b/samples/client/petstore/scala-sttp/src/main/scala/org/openapitools/client/core/DateSerializers.scala
@@ -0,0 +1,29 @@
+package org.openapitools.client.core
+
+import java.time.{LocalDate, LocalDateTime, OffsetDateTime, ZoneId}
+import java.time.format.DateTimeFormatter
+import scala.util.Try
+
+object DateSerializers {
+    import org.json4s.{Serializer, CustomSerializer, JNull}
+    import org.json4s.JsonAST.JString
+      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))
+      }))
+
+  def all: Seq[Serializer[_]] = Seq[Serializer[_]]() :+ LocalDateSerializer :+ DateTimeSerializer
+}
diff --git a/samples/client/petstore/scala-sttp/src/main/scala/org/openapitools/client/core/JsonSupport.scala b/samples/client/petstore/scala-sttp/src/main/scala/org/openapitools/client/core/JsonSupport.scala
index 33d158b6fd1..51896325c2a 100644
--- a/samples/client/petstore/scala-sttp/src/main/scala/org/openapitools/client/core/JsonSupport.scala
+++ b/samples/client/petstore/scala-sttp/src/main/scala/org/openapitools/client/core/JsonSupport.scala
@@ -43,6 +43,6 @@ object JsonSupport extends SttpJson4sApi {
       }
     }
 
-  implicit val format: Formats = DefaultFormats ++ enumSerializers ++ Serializers.all
+  implicit val format: Formats = DefaultFormats ++ enumSerializers ++ DateSerializers.all
   implicit val serialization: org.json4s.Serialization = org.json4s.jackson.Serialization
 }
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
deleted file mode 100644
index dbd13545c73..00000000000
--- a/samples/client/petstore/scala-sttp/src/main/scala/org/openapitools/client/core/Serializers.scala
+++ /dev/null
@@ -1,31 +0,0 @@
-package org.openapitools.client.core
-
-import java.time.{LocalDate, LocalDateTime, OffsetDateTime, ZoneId}
-import java.time.format.DateTimeFormatter
-import scala.util.Try
-import org.json4s.{Serializer, CustomSerializer, JNull}
-import org.json4s.JsonAST.JString
-
-object Serializers {
-
-  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))
-  }))
-
-  def all: Seq[Serializer[_]] = Seq[Serializer[_]]() :+ LocalDateSerializer :+ DateTimeSerializer
-
-}
-- 
GitLab


From 5cab35de96bab3f93b1fff6a930fdb3cb28e3aa0 Mon Sep 17 00:00:00 2001
From: ghostbuster91 <kghost0@gmail.com>
Date: Tue, 9 Jun 2020 12:19:10 +0200
Subject: [PATCH 17/38] Simplify credentials

---
 .../languages/ScalaSttpClientCodegen.java     |   2 +-
 .../resources/scala-sttp/credentials.mustache |   8 +
 .../resources/scala-sttp/requests.mustache    |  36 ----
 .../scala-sttp/.openapi-generator/FILES       |   2 +-
 .../org/openapitools/client/api/PetApi.scala  | 199 ++++++++++--------
 .../client/core/credentials.scala             |  18 ++
 .../openapitools/client/core/requests.scala   |  46 ----
 7 files changed, 136 insertions(+), 175 deletions(-)
 create mode 100644 modules/openapi-generator/src/main/resources/scala-sttp/credentials.mustache
 delete mode 100644 modules/openapi-generator/src/main/resources/scala-sttp/requests.mustache
 create mode 100644 samples/client/petstore/scala-sttp/src/main/scala/org/openapitools/client/core/credentials.scala
 delete mode 100644 samples/client/petstore/scala-sttp/src/main/scala/org/openapitools/client/core/requests.scala

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
index 4231b567bc2..96d336247f5 100644
--- 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
@@ -84,7 +84,7 @@ public class ScalaSttpClientCodegen extends ScalaAkkaClientCodegen implements Co
         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("credentials.mustache", invokerFolder, "credentials.scala"));
         supportingFiles.add(new SupportingFile("jsonSupport.mustache", invokerFolder, "JsonSupport.scala"));
         supportingFiles.add(new SupportingFile("project/build.properties.mustache", "project", "build.properties"));
         supportingFiles.add(new SupportingFile("dateSerializers.mustache", invokerFolder, "DateSerializers.scala"));
diff --git a/modules/openapi-generator/src/main/resources/scala-sttp/credentials.mustache b/modules/openapi-generator/src/main/resources/scala-sttp/credentials.mustache
new file mode 100644
index 00000000000..6fedf01459d
--- /dev/null
+++ b/modules/openapi-generator/src/main/resources/scala-sttp/credentials.mustache
@@ -0,0 +1,8 @@
+{{>licenseInfo}}
+package {{invokerPackage}}
+
+final case class BasicCredentials(user: String, password: String)
+
+final case class BearerToken(token: String)
+
+final case class ApiKeyValue(value: String)
diff --git a/modules/openapi-generator/src/main/resources/scala-sttp/requests.mustache b/modules/openapi-generator/src/main/resources/scala-sttp/requests.mustache
deleted file mode 100644
index 7e6e1212029..00000000000
--- a/modules/openapi-generator/src/main/resources/scala-sttp/requests.mustache
+++ /dev/null
@@ -1,36 +0,0 @@
-{{>licenseInfo}}
-package {{invokerPackage}}
-
-import sttp.client.{Identity, RequestT, ResponseError}
-
-/**
- * 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/.openapi-generator/FILES b/samples/client/petstore/scala-sttp/.openapi-generator/FILES
index 15444ab9209..dd8a280e233 100644
--- a/samples/client/petstore/scala-sttp/.openapi-generator/FILES
+++ b/samples/client/petstore/scala-sttp/.openapi-generator/FILES
@@ -6,7 +6,7 @@ src/main/scala/org/openapitools/client/api/StoreApi.scala
 src/main/scala/org/openapitools/client/api/UserApi.scala
 src/main/scala/org/openapitools/client/core/DateSerializers.scala
 src/main/scala/org/openapitools/client/core/JsonSupport.scala
-src/main/scala/org/openapitools/client/core/requests.scala
+src/main/scala/org/openapitools/client/core/credentials.scala
 src/main/scala/org/openapitools/client/model/ApiResponse.scala
 src/main/scala/org/openapitools/client/model/Category.scala
 src/main/scala/org/openapitools/client/model/InlineObject.scala
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
index 8e9be2c3795..af39ee5acb9 100644
--- 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
@@ -1,14 +1,14 @@
 /**
- * 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.
- */
+  * 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
@@ -22,13 +22,15 @@ import sttp.model.Method
 class PetApi(baseUrl: String = "http://petstore.swagger.io/v2") {
 
   /**
-   * 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): Request[Either[ResponseError[Exception], Pet], Nothing] =
+    * 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
+  ): Request[Either[ResponseError[Exception], Pet], Nothing] =
     basicRequest
       .method(Method.POST, uri"$baseUrl/pet")
       .contentType("application/json")
@@ -36,63 +38,71 @@ class PetApi(baseUrl: String = "http://petstore.swagger.io/v2") {
       .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): Request[Either[ResponseError[Exception], Unit], Nothing] =
+    * Expected answers:
+    *   code 400 :  (Invalid pet value)
+    *
+    * @param petId Pet id to delete
+    * @param apiKey
+    */
+  def deletePet(
+    petId: Long,
+    apiKey: Option[String] = None
+  ): Request[Either[ResponseError[Exception], Unit], Nothing] =
     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]): Request[Either[ResponseError[Exception], Seq[Pet]], Nothing] =
+    * 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]
+  ): Request[Either[ResponseError[Exception], Seq[Pet]], Nothing] =
     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]): Request[Either[ResponseError[Exception], Seq[Pet]], Nothing] =
+    * 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]
+  ): Request[Either[ResponseError[Exception], Seq[Pet]], Nothing] =
     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): Request[Either[ResponseError[Exception], Pet], Nothing] =
+    * 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
+  ): Request[Either[ResponseError[Exception], Pet], Nothing] =
     basicRequest
       .method(Method.GET, uri"$baseUrl/pet/${petId}")
       .contentType("application/json")
@@ -100,15 +110,17 @@ class PetApi(baseUrl: String = "http://petstore.swagger.io/v2") {
       .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): Request[Either[ResponseError[Exception], Pet], Nothing] =
+    * 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
+  ): Request[Either[ResponseError[Exception], Pet], Nothing] =
     basicRequest
       .method(Method.PUT, uri"$baseUrl/pet")
       .contentType("application/json")
@@ -116,41 +128,46 @@ class PetApi(baseUrl: String = "http://petstore.swagger.io/v2") {
       .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): Request[Either[ResponseError[Exception], Unit], Nothing] =
+    * 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
+  ): Request[Either[ResponseError[Exception], Unit], Nothing] =
     basicRequest
       .method(Method.POST, uri"$baseUrl/pet/${petId}")
       .contentType("application/x-www-form-urlencoded")
-      .body(Map(
-        "name" -> name, 
-        "status" -> status
-      ))
+      .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): Request[Either[ResponseError[Exception], ApiResponse], Nothing] =
+    * 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
+  ): Request[Either[ResponseError[Exception], ApiResponse], Nothing] =
     basicRequest
       .method(Method.POST, uri"$baseUrl/pet/${petId}/uploadImage")
       .contentType("multipart/form-data")
-      .multipartBody(Seq(
-                additionalMetadata.map(multipart("additionalMetadata", _))
-, 
-                file.map(multipartFile("file", _))
-
-      ).flatten)
+      .multipartBody(
+        Seq(
+          additionalMetadata.map(multipart("additionalMetadata", _)),
+          file.map(multipartFile("file", _))
+        ).flatten
+      )
       .response(asJson[ApiResponse])
 
 }
diff --git a/samples/client/petstore/scala-sttp/src/main/scala/org/openapitools/client/core/credentials.scala b/samples/client/petstore/scala-sttp/src/main/scala/org/openapitools/client/core/credentials.scala
new file mode 100644
index 00000000000..97d9ddcec81
--- /dev/null
+++ b/samples/client/petstore/scala-sttp/src/main/scala/org/openapitools/client/core/credentials.scala
@@ -0,0 +1,18 @@
+/**
+ * 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
+
+final case class BasicCredentials(user: String, password: String)
+
+final case class BearerToken(token: String)
+
+final case class ApiKeyValue(value: String)
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
deleted file mode 100644
index e1d4f3915cc..00000000000
--- a/samples/client/petstore/scala-sttp/src/main/scala/org/openapitools/client/core/requests.scala
+++ /dev/null
@@ -1,46 +0,0 @@
-/**
- * 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}
-
-/**
- * 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
-
-}
-- 
GitLab


From 714f93055040103b8671bd1a6d24c4a577173547 Mon Sep 17 00:00:00 2001
From: ghostbuster91 <kghost0@gmail.com>
Date: Tue, 9 Jun 2020 13:07:55 +0200
Subject: [PATCH 18/38] Simplify code

---
 .../codegen/languages/ScalaSttpClientCodegen.java | 15 +++++----------
 1 file changed, 5 insertions(+), 10 deletions(-)

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
index 96d336247f5..37a9e977fee 100644
--- 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
@@ -24,8 +24,6 @@ import org.openapitools.codegen.CodegenOperation;
 import org.openapitools.codegen.SupportingFile;
 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;
@@ -33,8 +31,6 @@ import java.util.List;
 import java.util.Map;
 
 public class ScalaSttpClientCodegen extends ScalaAkkaClientCodegen implements CodegenConfig {
-    private static final Logger LOGGER = LoggerFactory.getLogger(ScalaSttpClientCodegen.class);
-
     private static final StringProperty STTP_CLIENT_VERSION = new StringProperty("sttpClientVersion", "The version of " +
             "sttp " +
                                                                               "client", "2.1.5");
@@ -186,8 +182,6 @@ public class ScalaSttpClientCodegen extends ScalaAkkaClientCodegen implements Co
     private static class JsonLibraryProperty extends StringProperty {
         private static final String JSON4S = "json4s";
         private static final String CIRCE = "circe";
-        private static final String USE_CIRCE_PROPERTY = "circe";
-        private static final String USE_JSON4S_PROPERTY = "json4s";
 
         private JsonLibraryProperty() {
             super("jsonLibrary", "Json library to use. Possible values are: json4s and circe.", JSON4S);
@@ -197,11 +191,12 @@ public class ScalaSttpClientCodegen extends ScalaAkkaClientCodegen implements Co
         public void updateAdditionalProperties(Map<String, Object> additionalProperties) {
             String value = getValue(additionalProperties);
             if (value.equals(CIRCE) || value.equals(JSON4S)) {
-                additionalProperties.put(USE_CIRCE_PROPERTY, value.equals(CIRCE));
-                additionalProperties.put(USE_JSON4S_PROPERTY, value.equals(JSON4S));
+                additionalProperties.put(CIRCE, value.equals(CIRCE));
+                additionalProperties.put(JSON4S, value.equals(JSON4S));
             } else {
-                IllegalArgumentException exception = new IllegalArgumentException("Unsupported json library: " + value);
-                LOGGER.error("Unsupported json library " + value, exception);
+                IllegalArgumentException exception =
+                        new IllegalArgumentException("Invalid json library: " + value + ". Must be " + CIRCE + " " +
+                                "or " + JSON4S);
                 throw exception;
             }
         }
-- 
GitLab


From a5f0a054c019ea61091454cc5ff1494f6ac8b7ac Mon Sep 17 00:00:00 2001
From: ghostbuster91 <kghost0@gmail.com>
Date: Tue, 9 Jun 2020 13:15:36 +0200
Subject: [PATCH 19/38] Update docs

---
 docs/generators/scala-sttp.md                               | 6 ++++++
 .../codegen/languages/ScalaSttpClientCodegen.java           | 3 +--
 2 files changed, 7 insertions(+), 2 deletions(-)

diff --git a/docs/generators/scala-sttp.md b/docs/generators/scala-sttp.md
index 7561501ce2e..c8016761aa6 100644
--- a/docs/generators/scala-sttp.md
+++ b/docs/generators/scala-sttp.md
@@ -7,7 +7,13 @@ sidebar_label: scala-sttp
 | ------ | ----------- | ------ | ------- |
 |allowUnicodeIdentifiers|boolean, toggles whether unicode identifiers are allowed in names or not, default is false| |false|
 |apiPackage|package for generated api classes| |null|
+|sttpClientVersion|Option. Allows to override default version of sttp client library.|2.1.5
 |dateLibrary|Option. Date library to use|<dl><dt>**joda**</dt><dd>Joda (for legacy app)</dd><dt>**java8**</dt><dd>Java 8 native JSR310 (prefered for JDK 1.8+)</dd></dl>|java8|
+|jodaTimeVersion|Only if dateLibrary was set to joda. Allows to override default jodatime version.|2.10.6
+|json4sVersion|Only if jsonLibrary was set to json4s. Allows to override default json4s version.|3.6.8
+|circeVersion|Only if jsonLibrary was set to circe. Allows to override default circe version.|0.13.0 
+|jsonLibrary|Option. Json library to use|<dl><dt>**json4s**</dt>https://github.com/json4s/json4s<dt>**circe**</dt><dd>https://github.com/circe/circe</dd></dl>|json4s|
+|separateErrorChannel| Option. Whether to return response as `F[Either[ResponseError[ErrorType], ReturnType]]]` or to flatten response's error raising them through enclosing monad (`F[ReturnType]`).|false
 |disallowAdditionalPropertiesIfNotPresent|Specify the behavior when the 'additionalProperties' keyword is not present in the OAS document. If false: the 'additionalProperties' implementation is compliant with the OAS and JSON schema specifications. If true: when the 'additionalProperties' keyword is not present in a schema, the value of 'additionalProperties' is set to false, i.e. no additional properties are allowed. Note: this mode is not compliant with the JSON schema specification. This is the original openapi-generator behavior.This setting is currently ignored for OAS 2.0 documents:  1) When the 'additionalProperties' keyword is not present in a 2.0 schema, additional properties are NOT allowed.  2) Boolean values of the 'additionalProperties' keyword are ignored. It's as if additional properties are NOT allowed.Note: the root cause are issues #1369 and #1371, which must be resolved in the swagger-parser project.|<dl><dt>**false**</dt><dd>The 'additionalProperties' implementation is compliant with the OAS and JSON schema specifications.</dd><dt>**true**</dt><dd>when the 'additionalProperties' keyword is not present in a schema, the value of 'additionalProperties' is automatically set to false, i.e. no additional properties are allowed. Note: this mode is not compliant with the JSON schema specification. This is the original openapi-generator behavior.</dd></dl>|true|
 |ensureUniqueParams|Whether to ensure parameter names are unique in an operation (rename parameters that are not).| |true|
 |legacyDiscriminatorBehavior|This flag is used by OpenAPITools codegen to influence the processing of the discriminator attribute in OpenAPI documents. This flag has no impact if the OAS document does not use the discriminator attribute. The default value of this flag is set in each language-specific code generator (e.g. Python, Java, go...)using the method toModelName. Note to developers supporting a language generator in OpenAPITools; to fully support the discriminator attribute as defined in the OAS specification 3.x, language generators should set this flag to true by default; however this requires updating the mustache templates to generate a language-specific discriminator lookup function that iterates over {{#mappedModels}} and does not iterate over {{children}}, {{#anyOf}}, or {{#oneOf}}.|<dl><dt>**true**</dt><dd>The mapping in the discriminator includes descendent schemas that allOf inherit from self and the discriminator mapping schemas in the OAS document.</dd><dt>**false**</dt><dd>The mapping in the discriminator includes any descendent schemas that allOf inherit from self, any oneOf schemas, any anyOf schemas, any x-discriminator-values, and the discriminator mapping schemas in the OAS document AND Codegen validates that oneOf and anyOf schemas contain the required discriminator and throws an error if the discriminator is missing.</dd></dl>|true|
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
index 37a9e977fee..7c806212ce2 100644
--- 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
@@ -32,8 +32,7 @@ import java.util.Map;
 
 public class ScalaSttpClientCodegen extends ScalaAkkaClientCodegen implements CodegenConfig {
     private static final StringProperty STTP_CLIENT_VERSION = new StringProperty("sttpClientVersion", "The version of " +
-            "sttp " +
-                                                                              "client", "2.1.5");
+            "sttp client", "2.1.5");
     private static final BooleanProperty USE_SEPARATE_ERROR_CHANNEL = new BooleanProperty("separateErrorChannel",
             "Whether to " +
                     "return response as " +
-- 
GitLab


From dfca277654a9dc89f86bd1d281a0b1cfc18ffaf4 Mon Sep 17 00:00:00 2001
From: ghostbuster91 <kghost0@gmail.com>
Date: Tue, 9 Jun 2020 13:16:09 +0200
Subject: [PATCH 20/38] Fix auto formatting

---
 .../languages/ScalaSttpClientCodegen.java     | 19 +++++++++----------
 1 file changed, 9 insertions(+), 10 deletions(-)

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
index 7c806212ce2..70b59c1d3a0 100644
--- 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
@@ -34,12 +34,11 @@ public class ScalaSttpClientCodegen extends ScalaAkkaClientCodegen implements Co
     private static final StringProperty STTP_CLIENT_VERSION = new StringProperty("sttpClientVersion", "The version of " +
             "sttp client", "2.1.5");
     private static final BooleanProperty USE_SEPARATE_ERROR_CHANNEL = new BooleanProperty("separateErrorChannel",
-            "Whether to " +
-                    "return response as " +
+            "Whether to return response as " +
                     "F[Either[ResponseError[ErrorType], ReturnType]]] or to flatten " +
                     "response's error raising them through enclosing monad (F[ReturnType]).", true);
-    private static final StringProperty JODA_TIME_VERSION = new StringProperty("jodaTimeVersion","The version of " +
-            "joda-time library","2.10.6");
+    private static final StringProperty JODA_TIME_VERSION = new StringProperty("jodaTimeVersion", "The version of " +
+            "joda-time library", "2.10.6");
     private static final StringProperty JSON4S_VERSION = new StringProperty("json4sVersion", "The version of json4s " +
             "library", "3.6.8");
     private static final StringProperty CIRCE_VERSION = new StringProperty("circeVersion", "The version of circe " +
@@ -58,7 +57,7 @@ public class ScalaSttpClientCodegen extends ScalaAkkaClientCodegen implements Co
         embeddedTemplateDir = templateDir = "scala-sttp";
         outputFolder = "generated-code/scala-sttp";
 
-        properties.forEach(p-> cliOptions.add(p.toCliOption()));
+        properties.forEach(p -> cliOptions.add(p.toCliOption()));
     }
 
     @Override
@@ -73,7 +72,7 @@ public class ScalaSttpClientCodegen extends ScalaAkkaClientCodegen implements Co
             additionalProperties.put("apiPackage", apiPackage);
             additionalProperties.put("modelPackage", modelPackage);
         }
-        properties.forEach(p-> p.updateAdditionalProperties(additionalProperties));
+        properties.forEach(p -> p.updateAdditionalProperties(additionalProperties));
 
         supportingFiles.clear();
         supportingFiles.add(new SupportingFile("README.mustache", "", "README.md"));
@@ -126,9 +125,9 @@ public class ScalaSttpClientCodegen extends ScalaAkkaClientCodegen implements Co
 
         public abstract void updateAdditionalProperties(Map<String, Object> additionalProperties);
 
-        public abstract T getValue(Map<String,Object> additionalProperties);
+        public abstract T getValue(Map<String, Object> additionalProperties);
 
-        public void setValue(Map<String,Object> additionalProperties, T value ) {
+        public void setValue(Map<String, Object> additionalProperties, T value) {
             additionalProperties.put(name, value);
         }
     }
@@ -145,14 +144,14 @@ public class ScalaSttpClientCodegen extends ScalaAkkaClientCodegen implements Co
 
         @Override
         public void updateAdditionalProperties(Map<String, Object> additionalProperties) {
-            if(!additionalProperties.containsKey(name)) {
+            if (!additionalProperties.containsKey(name)) {
                 additionalProperties.put(name, defaultValue);
             }
         }
 
         @Override
         public String getValue(Map<String, Object> additionalProperties) {
-            return additionalProperties.getOrDefault(name,defaultValue).toString();
+            return additionalProperties.getOrDefault(name, defaultValue).toString();
         }
     }
 
-- 
GitLab


From 5efad875885d024c4da466d7d0282f6224445c4c Mon Sep 17 00:00:00 2001
From: ghostbuster91 <kghost0@gmail.com>
Date: Tue, 9 Jun 2020 16:52:41 +0200
Subject: [PATCH 21/38] Simplify code

---
 .../org/openapitools/client/api/PetApi.scala  | 199 ++++++++----------
 1 file changed, 91 insertions(+), 108 deletions(-)

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
index af39ee5acb9..8e9be2c3795 100644
--- 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
@@ -1,14 +1,14 @@
 /**
-  * 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.
-  */
+ * 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
@@ -22,15 +22,13 @@ import sttp.model.Method
 class PetApi(baseUrl: String = "http://petstore.swagger.io/v2") {
 
   /**
-    * 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
-  ): Request[Either[ResponseError[Exception], Pet], Nothing] =
+   * 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): Request[Either[ResponseError[Exception], Pet], Nothing] =
     basicRequest
       .method(Method.POST, uri"$baseUrl/pet")
       .contentType("application/json")
@@ -38,71 +36,63 @@ class PetApi(baseUrl: String = "http://petstore.swagger.io/v2") {
       .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
-  ): Request[Either[ResponseError[Exception], Unit], Nothing] =
+   * Expected answers:
+   *   code 400 :  (Invalid pet value)
+   * 
+   * @param petId Pet id to delete
+   * @param apiKey 
+   */
+  def deletePet(petId: Long, apiKey: Option[String] = None): Request[Either[ResponseError[Exception], Unit], Nothing] =
     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]
-  ): Request[Either[ResponseError[Exception], Seq[Pet]], Nothing] =
+   * 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]): Request[Either[ResponseError[Exception], Seq[Pet]], Nothing] =
     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]
-  ): Request[Either[ResponseError[Exception], Seq[Pet]], Nothing] =
+   * 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]): Request[Either[ResponseError[Exception], Seq[Pet]], Nothing] =
     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
-  ): Request[Either[ResponseError[Exception], Pet], Nothing] =
+   * 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): Request[Either[ResponseError[Exception], Pet], Nothing] =
     basicRequest
       .method(Method.GET, uri"$baseUrl/pet/${petId}")
       .contentType("application/json")
@@ -110,17 +100,15 @@ class PetApi(baseUrl: String = "http://petstore.swagger.io/v2") {
       .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
-  ): Request[Either[ResponseError[Exception], Pet], Nothing] =
+   * 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): Request[Either[ResponseError[Exception], Pet], Nothing] =
     basicRequest
       .method(Method.PUT, uri"$baseUrl/pet")
       .contentType("application/json")
@@ -128,46 +116,41 @@ class PetApi(baseUrl: String = "http://petstore.swagger.io/v2") {
       .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
-  ): Request[Either[ResponseError[Exception], Unit], Nothing] =
+   * 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): Request[Either[ResponseError[Exception], Unit], Nothing] =
     basicRequest
       .method(Method.POST, uri"$baseUrl/pet/${petId}")
       .contentType("application/x-www-form-urlencoded")
-      .body(Map("name" -> name, "status" -> status))
+      .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
-  ): Request[Either[ResponseError[Exception], ApiResponse], Nothing] =
+   * 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): Request[Either[ResponseError[Exception], ApiResponse], Nothing] =
     basicRequest
       .method(Method.POST, uri"$baseUrl/pet/${petId}/uploadImage")
       .contentType("multipart/form-data")
-      .multipartBody(
-        Seq(
-          additionalMetadata.map(multipart("additionalMetadata", _)),
-          file.map(multipartFile("file", _))
-        ).flatten
-      )
+      .multipartBody(Seq(
+                additionalMetadata.map(multipart("additionalMetadata", _))
+, 
+                file.map(multipartFile("file", _))
+
+      ).flatten)
       .response(asJson[ApiResponse])
 
 }
-- 
GitLab


From 3c836f9296f38e5f50fa39cfbe80ca8f450cdfe6 Mon Sep 17 00:00:00 2001
From: ghostbuster91 <kghost0@gmail.com>
Date: Tue, 9 Jun 2020 16:54:06 +0200
Subject: [PATCH 22/38] SttpCodegen should not depend on akka

---
 .../languages/ScalaSttpClientCodegen.java     | 316 +++++++++++++++++-
 1 file changed, 300 insertions(+), 16 deletions(-)

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
index 70b59c1d3a0..131102cf03d 100644
--- 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
@@ -16,21 +16,31 @@
 
 package org.openapitools.codegen.languages;
 
+import com.samskivert.mustache.Mustache;
+import com.samskivert.mustache.Template;
 import io.swagger.v3.oas.models.Operation;
+import io.swagger.v3.oas.models.media.ArraySchema;
+import io.swagger.v3.oas.models.media.Schema;
+import io.swagger.v3.oas.models.security.SecurityScheme;
 import io.swagger.v3.oas.models.servers.Server;
-import org.openapitools.codegen.CliOption;
-import org.openapitools.codegen.CodegenConfig;
-import org.openapitools.codegen.CodegenOperation;
-import org.openapitools.codegen.SupportingFile;
+import org.apache.commons.lang3.StringUtils;
+import org.openapitools.codegen.*;
 import org.openapitools.codegen.meta.GeneratorMetadata;
 import org.openapitools.codegen.meta.Stability;
+import org.openapitools.codegen.meta.features.*;
+import org.openapitools.codegen.utils.ModelUtils;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
 
 import java.io.File;
-import java.util.Arrays;
-import java.util.List;
-import java.util.Map;
+import java.io.IOException;
+import java.io.StringWriter;
+import java.io.Writer;
+import java.util.*;
 
-public class ScalaSttpClientCodegen extends ScalaAkkaClientCodegen implements CodegenConfig {
+import static org.openapitools.codegen.utils.StringUtils.camelize;
+
+public class ScalaSttpClientCodegen extends AbstractScalaCodegen implements CodegenConfig {
     private static final StringProperty STTP_CLIENT_VERSION = new StringProperty("sttpClientVersion", "The version of " +
             "sttp client", "2.1.5");
     private static final BooleanProperty USE_SEPARATE_ERROR_CHANNEL = new BooleanProperty("separateErrorChannel",
@@ -44,9 +54,25 @@ public class ScalaSttpClientCodegen extends ScalaAkkaClientCodegen implements Co
     private static final StringProperty CIRCE_VERSION = new StringProperty("circeVersion", "The version of circe " +
             "library", "0.13.0");
     private static final JsonLibraryProperty JSON_LIBRARY_PROPERTY = new JsonLibraryProperty();
+    private static final StringProperty MAIN_PACKAGE = new StringProperty("mainPackage","Top-level package name, " +
+            "which defines 'apiPackage', 'modelPackage', 'invokerPackage'","org.openapitools.client");
 
     private static final List<Property> properties = Arrays.asList(STTP_CLIENT_VERSION, USE_SEPARATE_ERROR_CHANNEL,
-            JODA_TIME_VERSION, JSON4S_VERSION, CIRCE_VERSION, JSON_LIBRARY_PROPERTY);
+            JODA_TIME_VERSION, JSON4S_VERSION, CIRCE_VERSION, JSON_LIBRARY_PROPERTY, MAIN_PACKAGE);
+
+    private final Logger LOGGER = LoggerFactory.getLogger(ScalaSttpClientCodegen.class);
+
+    protected String mainPackage = "org.openapitools.client";
+    protected String groupId = "org.openapitools";
+    protected String artifactId = "openapi-client";
+    protected String artifactVersion = "1.0.0";
+    protected String resourcesFolder = "src/main/resources";
+    protected String configKey = "apiRequest";
+    protected int defaultTimeoutInMs = 5000;
+    protected String configKeyPath = mainPackage;
+    protected boolean registerNonStandardStatusCodes = true;
+    protected boolean renderJavadoc = true;
+    protected boolean removeOAuthSecurities = true;
 
     public ScalaSttpClientCodegen() {
         super();
@@ -54,8 +80,87 @@ public class ScalaSttpClientCodegen extends ScalaAkkaClientCodegen implements Co
                 .stability(Stability.BETA)
                 .build();
 
-        embeddedTemplateDir = templateDir = "scala-sttp";
+        modifyFeatureSet(features -> features
+                .includeDocumentationFeatures(DocumentationFeature.Readme)
+                .wireFormatFeatures(EnumSet.of(WireFormatFeature.JSON, WireFormatFeature.XML, WireFormatFeature.Custom))
+                .securityFeatures(EnumSet.of(
+                        SecurityFeature.BasicAuth,
+                        SecurityFeature.ApiKey,
+                        SecurityFeature.BearerToken
+                ))
+                .excludeGlobalFeatures(
+                        GlobalFeature.XMLStructureDefinitions,
+                        GlobalFeature.Callbacks,
+                        GlobalFeature.LinkObjects,
+                        GlobalFeature.ParameterStyling
+                )
+                .excludeSchemaSupportFeatures(
+                        SchemaSupportFeature.Polymorphism
+                )
+                .excludeParameterFeatures(
+                        ParameterFeature.Cookie
+                )
+                .includeClientModificationFeatures(
+                        ClientModificationFeature.BasePath,
+                        ClientModificationFeature.UserAgent
+                )
+        );
+
         outputFolder = "generated-code/scala-sttp";
+        modelTemplateFiles.put("model.mustache", ".scala");
+        apiTemplateFiles.put("api.mustache", ".scala");
+        embeddedTemplateDir = templateDir = "scala-sttp";
+        apiPackage = mainPackage + ".api";
+        modelPackage = mainPackage + ".model";
+        invokerPackage = mainPackage + ".core";
+
+        setReservedWordsLowerCase(
+                Arrays.asList(
+                        "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", "try", "true", "type", "val", "var", "while", "with", "yield")
+        );
+
+        additionalProperties.put(CodegenConstants.GROUP_ID, groupId);
+        additionalProperties.put(CodegenConstants.ARTIFACT_ID, artifactId);
+        additionalProperties.put(CodegenConstants.ARTIFACT_VERSION, artifactVersion);
+        additionalProperties.put("configKey", configKey);
+        additionalProperties.put("configKeyPath", configKeyPath);
+        additionalProperties.put("defaultTimeout", defaultTimeoutInMs);
+        if (renderJavadoc) {
+            additionalProperties.put("javadocRenderer", new JavadocLambda());
+        }
+        additionalProperties.put("fnCapitalize", new CapitalizeLambda());
+        additionalProperties.put("fnCamelize", new CamelizeLambda(false));
+        additionalProperties.put("fnEnumEntry", new EnumEntryLambda());
+
+        importMapping.remove("Seq");
+        importMapping.remove("List");
+        importMapping.remove("Set");
+        importMapping.remove("Map");
+
+        typeMapping = new HashMap<>();
+        typeMapping.put("array", "Seq");
+        typeMapping.put("set", "Set");
+        typeMapping.put("boolean", "Boolean");
+        typeMapping.put("string", "String");
+        typeMapping.put("int", "Int");
+        typeMapping.put("integer", "Int");
+        typeMapping.put("long", "Long");
+        typeMapping.put("float", "Float");
+        typeMapping.put("byte", "Byte");
+        typeMapping.put("short", "Short");
+        typeMapping.put("char", "Char");
+        typeMapping.put("double", "Double");
+        typeMapping.put("object", "Any");
+        typeMapping.put("file", "File");
+        typeMapping.put("binary", "File");
+        typeMapping.put("number", "Double");
+
+        instantiationTypes.put("array", "ListBuffer");
+        instantiationTypes.put("map", "Map");
 
         properties.forEach(p -> cliOptions.add(p.toCliOption()));
     }
@@ -63,18 +168,27 @@ public class ScalaSttpClientCodegen extends ScalaAkkaClientCodegen implements Co
     @Override
     public void processOpts() {
         super.processOpts();
+        if (additionalProperties.containsKey(CodegenConstants.INVOKER_PACKAGE)) {
+            this.setInvokerPackage((String) additionalProperties.get(CodegenConstants.INVOKER_PACKAGE));
+        }
         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(CodegenConstants.API_PACKAGE)){
+                apiPackage = mainPackage + ".api";
+                additionalProperties.put(CodegenConstants.API_PACKAGE, apiPackage);
+            }
+            if (!additionalProperties.containsKey(CodegenConstants.MODEL_PACKAGE)){
+                modelPackage = mainPackage + ".model";
+                additionalProperties.put(CodegenConstants.MODEL_PACKAGE, modelPackage);
+            }
+            if (!additionalProperties.containsKey(CodegenConstants.INVOKER_PACKAGE)){
+                invokerPackage = mainPackage + ".core";
+            }
         }
+        additionalProperties.put(CodegenConstants.INVOKER_PACKAGE, invokerPackage);
         properties.forEach(p -> p.updateAdditionalProperties(additionalProperties));
 
-        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);
@@ -110,6 +224,122 @@ public class ScalaSttpClientCodegen extends ScalaAkkaClientCodegen implements Co
         return op;
     }
 
+    @Override
+    public CodegenType getTag() {
+        return CodegenType.CLIENT;
+    }
+
+    @Override
+    public String escapeReservedWord(String name) {
+        if (this.reservedWordsMappings().containsKey(name)) {
+            return this.reservedWordsMappings().get(name);
+        }
+        return "`" + name + "`";
+    }
+
+    @Override
+    public Map<String, Object> postProcessOperationsWithModels(Map<String, Object> objs, List<Object> allModels) {
+        if (registerNonStandardStatusCodes) {
+            try {
+                @SuppressWarnings("unchecked")
+                Map<String, ArrayList<CodegenOperation>> opsMap = (Map<String, ArrayList<CodegenOperation>>) objs.get("operations");
+                HashSet<Integer> unknownCodes = new HashSet<Integer>();
+                for (CodegenOperation operation : opsMap.get("operation")) {
+                    for (CodegenResponse response : operation.responses) {
+                        if ("default".equals(response.code)) {
+                            continue;
+                        }
+                        try {
+                            int code = Integer.parseInt(response.code);
+                            if (code >= 600) {
+                                unknownCodes.add(code);
+                            }
+                        } catch (NumberFormatException e) {
+                            LOGGER.error("Status code is not an integer : response.code", e);
+                        }
+                    }
+                }
+                if (!unknownCodes.isEmpty()) {
+                    additionalProperties.put("unknownStatusCodes", unknownCodes);
+                }
+            } catch (Exception e) {
+                LOGGER.error("Unable to find operations List", e);
+            }
+        }
+        return super.postProcessOperationsWithModels(objs, allModels);
+    }
+
+    @Override
+    public List<CodegenSecurity> fromSecurity(Map<String, SecurityScheme> schemes) {
+        final List<CodegenSecurity> codegenSecurities = super.fromSecurity(schemes);
+        if (!removeOAuthSecurities) {
+            return codegenSecurities;
+        }
+
+        // Remove OAuth securities
+        Iterator<CodegenSecurity> it = codegenSecurities.iterator();
+        while (it.hasNext()) {
+            final CodegenSecurity security = it.next();
+            if (security.isOAuth) {
+                it.remove();
+            }
+        }
+        // Adapt 'hasMore'
+        it = codegenSecurities.iterator();
+        while (it.hasNext()) {
+            final CodegenSecurity security = it.next();
+            security.hasMore = it.hasNext();
+        }
+
+        if (codegenSecurities.isEmpty()) {
+            return null;
+        }
+        return codegenSecurities;
+    }
+
+    @Override
+    public String toParamName(String name) {
+        return formatIdentifier(name, false);
+    }
+
+    @Override
+    public String toEnumName(CodegenProperty property) {
+        return formatIdentifier(property.baseName, true);
+    }
+
+    @Override
+    public String toDefaultValue(Schema p) {
+        if (p.getRequired() != null && p.getRequired().contains(p.getName())) {
+            return "None";
+        }
+
+        if (ModelUtils.isBooleanSchema(p)) {
+            return null;
+        } else if (ModelUtils.isDateSchema(p)) {
+            return null;
+        } else if (ModelUtils.isDateTimeSchema(p)) {
+            return null;
+        } else if (ModelUtils.isNumberSchema(p)) {
+            return null;
+        } else if (ModelUtils.isIntegerSchema(p)) {
+            return null;
+        } else if (ModelUtils.isMapSchema(p)) {
+            String inner = getSchemaType(getAdditionalProperties(p));
+            return "Map[String, " + inner + "].empty ";
+        } else if (ModelUtils.isArraySchema(p)) {
+            ArraySchema ap = (ArraySchema) p;
+            String inner = getSchemaType(ap.getItems());
+            if (ModelUtils.isSet(ap)) {
+                return "Set[" + inner + "].empty ";
+            }
+            return "Seq[" + inner + "].empty ";
+        } else if (ModelUtils.isStringSchema(p)) {
+            return null;
+        } else {
+            return null;
+        }
+    }
+
     private static abstract class Property<T> {
         final String name;
         final String description;
@@ -199,5 +429,59 @@ public class ScalaSttpClientCodegen extends ScalaAkkaClientCodegen implements Co
             }
         }
     }
+    private static abstract class CustomLambda implements Mustache.Lambda {
+        @Override
+        public void execute(Template.Fragment frag, Writer out) throws IOException {
+            final StringWriter tempWriter = new StringWriter();
+            frag.execute(tempWriter);
+            out.write(formatFragment(tempWriter.toString()));
+        }
+
+        public abstract String formatFragment(String fragment);
+    }
+
+    private static class JavadocLambda extends CustomLambda {
+        @Override
+        public String formatFragment(String fragment) {
+            final String[] lines = fragment.split("\\r?\\n");
+            final StringBuilder sb = new StringBuilder();
+            sb.append("  /**\n");
+            for (String line : lines) {
+                sb.append("   * ").append(line).append("\n");
+            }
+            sb.append("   */\n");
+            return sb.toString();
+        }
+    }
+
+    private static class CapitalizeLambda extends CustomLambda {
+        @Override
+        public String formatFragment(String fragment) {
+            return StringUtils.capitalize(fragment);
+        }
+    }
 
+    private static class CamelizeLambda extends CustomLambda {
+        private final boolean capitalizeFirst;
+
+        public CamelizeLambda(boolean capitalizeFirst) {
+            this.capitalizeFirst = capitalizeFirst;
+        }
+
+        @Override
+        public String formatFragment(String fragment) {
+            return camelize(fragment, !capitalizeFirst);
+        }
+    }
+
+    private class EnumEntryLambda extends CustomLambda {
+        @Override
+        public String formatFragment(String fragment) {
+            return formatIdentifier(fragment, true);
+        }
+    }
+
+    public void setMainPackage(String mainPackage) {
+        this.configKeyPath = this.mainPackage = mainPackage;
+    }
 }
-- 
GitLab


From a377921a832828e5497bdfc74f5ab58828f97710 Mon Sep 17 00:00:00 2001
From: ghostbuster91 <kghost0@gmail.com>
Date: Wed, 10 Jun 2020 09:30:23 +0200
Subject: [PATCH 23/38] Rewrite properties handling

---
 .../languages/ScalaSttpClientCodegen.java     | 74 +++++++++++--------
 1 file changed, 42 insertions(+), 32 deletions(-)

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
index 131102cf03d..eb32315bb17 100644
--- 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
@@ -54,11 +54,19 @@ public class ScalaSttpClientCodegen extends AbstractScalaCodegen implements Code
     private static final StringProperty CIRCE_VERSION = new StringProperty("circeVersion", "The version of circe " +
             "library", "0.13.0");
     private static final JsonLibraryProperty JSON_LIBRARY_PROPERTY = new JsonLibraryProperty();
-    private static final StringProperty MAIN_PACKAGE = new StringProperty("mainPackage","Top-level package name, " +
-            "which defines 'apiPackage', 'modelPackage', 'invokerPackage'","org.openapitools.client");
+
+    private static final String DEFAULT_PACKAGE_NAME = "org.openapitools.client";
+    private static final MainPackageProperty MAIN_PACKAGE = new MainPackageProperty();
+    private static final StringProperty MODEL_PACKAGE = new StringProperty(CodegenConstants.MODEL_PACKAGE,
+            CodegenConstants.MODEL_PACKAGE_DESC, DEFAULT_PACKAGE_NAME + ".model");
+    private static final StringProperty INVOKER_PACKAGE = new StringProperty(CodegenConstants.INVOKER_PACKAGE,
+            CodegenConstants.MODEL_PACKAGE_DESC, DEFAULT_PACKAGE_NAME + ".core");
+    private static final StringProperty API_PACKAGE = new StringProperty(CodegenConstants.API_PACKAGE,
+            CodegenConstants.API_PACKAGE_DESC, DEFAULT_PACKAGE_NAME + ".api");
 
     private static final List<Property> properties = Arrays.asList(STTP_CLIENT_VERSION, USE_SEPARATE_ERROR_CHANNEL,
-            JODA_TIME_VERSION, JSON4S_VERSION, CIRCE_VERSION, JSON_LIBRARY_PROPERTY, MAIN_PACKAGE);
+            JODA_TIME_VERSION, JSON4S_VERSION, CIRCE_VERSION, JSON_LIBRARY_PROPERTY,MAIN_PACKAGE, API_PACKAGE,
+            MODEL_PACKAGE, INVOKER_PACKAGE);
 
     private final Logger LOGGER = LoggerFactory.getLogger(ScalaSttpClientCodegen.class);
 
@@ -66,10 +74,6 @@ public class ScalaSttpClientCodegen extends AbstractScalaCodegen implements Code
     protected String groupId = "org.openapitools";
     protected String artifactId = "openapi-client";
     protected String artifactVersion = "1.0.0";
-    protected String resourcesFolder = "src/main/resources";
-    protected String configKey = "apiRequest";
-    protected int defaultTimeoutInMs = 5000;
-    protected String configKeyPath = mainPackage;
     protected boolean registerNonStandardStatusCodes = true;
     protected boolean renderJavadoc = true;
     protected boolean removeOAuthSecurities = true;
@@ -126,9 +130,6 @@ public class ScalaSttpClientCodegen extends AbstractScalaCodegen implements Code
         additionalProperties.put(CodegenConstants.GROUP_ID, groupId);
         additionalProperties.put(CodegenConstants.ARTIFACT_ID, artifactId);
         additionalProperties.put(CodegenConstants.ARTIFACT_VERSION, artifactVersion);
-        additionalProperties.put("configKey", configKey);
-        additionalProperties.put("configKeyPath", configKeyPath);
-        additionalProperties.put("defaultTimeout", defaultTimeoutInMs);
         if (renderJavadoc) {
             additionalProperties.put("javadocRenderer", new JavadocLambda());
         }
@@ -168,26 +169,10 @@ public class ScalaSttpClientCodegen extends AbstractScalaCodegen implements Code
     @Override
     public void processOpts() {
         super.processOpts();
-        if (additionalProperties.containsKey(CodegenConstants.INVOKER_PACKAGE)) {
-            this.setInvokerPackage((String) additionalProperties.get(CodegenConstants.INVOKER_PACKAGE));
-        }
-        if (additionalProperties.containsKey("mainPackage")) {
-            setMainPackage((String) additionalProperties.get("mainPackage"));
-            additionalProperties.replace("configKeyPath", this.configKeyPath);
-            if (!additionalProperties.containsKey(CodegenConstants.API_PACKAGE)){
-                apiPackage = mainPackage + ".api";
-                additionalProperties.put(CodegenConstants.API_PACKAGE, apiPackage);
-            }
-            if (!additionalProperties.containsKey(CodegenConstants.MODEL_PACKAGE)){
-                modelPackage = mainPackage + ".model";
-                additionalProperties.put(CodegenConstants.MODEL_PACKAGE, modelPackage);
-            }
-            if (!additionalProperties.containsKey(CodegenConstants.INVOKER_PACKAGE)){
-                invokerPackage = mainPackage + ".core";
-            }
-        }
-        additionalProperties.put(CodegenConstants.INVOKER_PACKAGE, invokerPackage);
         properties.forEach(p -> p.updateAdditionalProperties(additionalProperties));
+        invokerPackage = INVOKER_PACKAGE.getValue(additionalProperties);
+        apiPackage = API_PACKAGE.getValue(additionalProperties);
+        modelPackage = MODEL_PACKAGE.getValue(additionalProperties);
 
         supportingFiles.add(new SupportingFile("README.mustache", "", "README.md"));
         supportingFiles.add(new SupportingFile("build.sbt.mustache", "", "build.sbt"));
@@ -429,6 +414,34 @@ public class ScalaSttpClientCodegen extends AbstractScalaCodegen implements Code
             }
         }
     }
+
+    private static class MainPackageProperty extends StringProperty {
+
+        private MainPackageProperty() {
+            super("mainPackage", "Top-level package name, which defines 'apiPackage', 'modelPackage', " +
+                    "'invokerPackage'", DEFAULT_PACKAGE_NAME);
+        }
+
+        @Override
+        public void updateAdditionalProperties(Map<String, Object> additionalProperties) {
+            if (additionalProperties.containsKey(name)) {
+                String mainPackage = (String) additionalProperties.get(name);
+                if (!additionalProperties.containsKey(CodegenConstants.API_PACKAGE)){
+                    String apiPackage = mainPackage + ".api";
+                    additionalProperties.put(CodegenConstants.API_PACKAGE, apiPackage);
+                }
+                if (!additionalProperties.containsKey(CodegenConstants.MODEL_PACKAGE)){
+                    String modelPackage = mainPackage + ".model";
+                    additionalProperties.put(CodegenConstants.MODEL_PACKAGE, modelPackage);
+                }
+                if (!additionalProperties.containsKey(CodegenConstants.INVOKER_PACKAGE)){
+                    String invokerPackage = mainPackage + ".core";
+                    additionalProperties.put(CodegenConstants.INVOKER_PACKAGE, invokerPackage);
+                }
+            }
+        }
+    }
+
     private static abstract class CustomLambda implements Mustache.Lambda {
         @Override
         public void execute(Template.Fragment frag, Writer out) throws IOException {
@@ -481,7 +494,4 @@ public class ScalaSttpClientCodegen extends AbstractScalaCodegen implements Code
         }
     }
 
-    public void setMainPackage(String mainPackage) {
-        this.configKeyPath = this.mainPackage = mainPackage;
-    }
 }
-- 
GitLab


From d176eebb61def78e848e089636b12335d35a2b63 Mon Sep 17 00:00:00 2001
From: ghostbuster91 <kghost0@gmail.com>
Date: Wed, 10 Jun 2020 12:57:01 +0200
Subject: [PATCH 24/38] Fix mainProperty application

---
 .../openapitools/codegen/languages/ScalaSttpClientCodegen.java  | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

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
index eb32315bb17..3b1642555d5 100644
--- 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
@@ -425,7 +425,7 @@ public class ScalaSttpClientCodegen extends AbstractScalaCodegen implements Code
         @Override
         public void updateAdditionalProperties(Map<String, Object> additionalProperties) {
             if (additionalProperties.containsKey(name)) {
-                String mainPackage = (String) additionalProperties.get(name);
+                String mainPackage = getValue(additionalProperties);
                 if (!additionalProperties.containsKey(CodegenConstants.API_PACKAGE)){
                     String apiPackage = mainPackage + ".api";
                     additionalProperties.put(CodegenConstants.API_PACKAGE, apiPackage);
-- 
GitLab


From f7c384c01a5e878255f0b65c1c541359872a7c04 Mon Sep 17 00:00:00 2001
From: ghostbuster91 <kghost0@gmail.com>
Date: Wed, 10 Jun 2020 13:15:10 +0200
Subject: [PATCH 25/38] Pass credentials to methods as regular parameters

---
 .../languages/ScalaSttpClientCodegen.java     |   1 -
 .../main/resources/scala-sttp/api.mustache    |   8 +-
 .../resources/scala-sttp/credentials.mustache |   8 --
 .../scala-sttp/methodParameters.mustache      |   2 +-
 .../scala-sttp/.openapi-generator/FILES       |   1 -
 .../org/openapitools/client/api/PetApi.scala  |  26 +++--
 .../openapitools/client/api/StoreApi.scala    | 100 ++++++++++--------
 .../org/openapitools/client/api/UserApi.scala |  36 ++++---
 8 files changed, 98 insertions(+), 84 deletions(-)
 delete mode 100644 modules/openapi-generator/src/main/resources/scala-sttp/credentials.mustache

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
index 3b1642555d5..bb1fdf42df8 100644
--- 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
@@ -177,7 +177,6 @@ public class ScalaSttpClientCodegen extends AbstractScalaCodegen implements Code
         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("credentials.mustache", invokerFolder, "credentials.scala"));
         supportingFiles.add(new SupportingFile("jsonSupport.mustache", invokerFolder, "JsonSupport.scala"));
         supportingFiles.add(new SupportingFile("project/build.properties.mustache", "project", "build.properties"));
         supportingFiles.add(new SupportingFile("dateSerializers.mustache", invokerFolder, "DateSerializers.scala"));
diff --git a/modules/openapi-generator/src/main/resources/scala-sttp/api.mustache b/modules/openapi-generator/src/main/resources/scala-sttp/api.mustache
index 6aa459ac179..ebb209c2422 100644
--- a/modules/openapi-generator/src/main/resources/scala-sttp/api.mustache
+++ b/modules/openapi-generator/src/main/resources/scala-sttp/api.mustache
@@ -21,10 +21,10 @@ class {{classname}}(baseUrl: String = "{{{basePath}}}") {
       .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}}{{^isMultipart}}
+      .auth.withCredentials(username, password){{/isBasicBasic}}{{#isBasicBearer}}
+      .auth.bearer(bearerToken){{/isBasicBearer}}{{/isBasic}}{{#isApiKey}}{{#isKeyInHeader}}
+      .header("{{keyParamName}}", apiKey){{/isKeyInHeader}}{{#isKeyInCookie}}
+      .cookie("{{keyParamName}}", apiKey){{/isKeyInCookie}}{{/isApiKey}}{{/authMethods}}{{#formParams.0}}{{^isMultipart}}
       .body(Map({{#formParams}}
         {{>paramFormCreation}}{{#hasMore}}, {{/hasMore}}{{/formParams}}
       )){{/isMultipart}}{{#isMultipart}}
diff --git a/modules/openapi-generator/src/main/resources/scala-sttp/credentials.mustache b/modules/openapi-generator/src/main/resources/scala-sttp/credentials.mustache
deleted file mode 100644
index 6fedf01459d..00000000000
--- a/modules/openapi-generator/src/main/resources/scala-sttp/credentials.mustache
+++ /dev/null
@@ -1,8 +0,0 @@
-{{>licenseInfo}}
-package {{invokerPackage}}
-
-final case class BasicCredentials(user: String, password: String)
-
-final case class BearerToken(token: String)
-
-final case class ApiKeyValue(value: String)
diff --git a/modules/openapi-generator/src/main/resources/scala-sttp/methodParameters.mustache b/modules/openapi-generator/src/main/resources/scala-sttp/methodParameters.mustache
index 54dc2f92a51..88d0e0d35fb 100644
--- a/modules/openapi-generator/src/main/resources/scala-sttp/methodParameters.mustache
+++ b/modules/openapi-generator/src/main/resources/scala-sttp/methodParameters.mustache
@@ -1 +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
+{{#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}}{{#allParams.0}}, {{/allParams.0}}{{#authMethods}}{{#isApiKey}}apiKey: String{{/isApiKey}}{{#isBasic}}{{#isBasicBasic}}username: String, password: String{{/isBasicBasic}}{{#isBasicBearer}}bearerToken: String{{/isBasicBearer}}{{/isBasic}}{{#hasMore}}, {{/hasMore}}{{/authMethods}}{{/authMethods.0}}
diff --git a/samples/client/petstore/scala-sttp/.openapi-generator/FILES b/samples/client/petstore/scala-sttp/.openapi-generator/FILES
index dd8a280e233..bf41f88a7b3 100644
--- a/samples/client/petstore/scala-sttp/.openapi-generator/FILES
+++ b/samples/client/petstore/scala-sttp/.openapi-generator/FILES
@@ -6,7 +6,6 @@ src/main/scala/org/openapitools/client/api/StoreApi.scala
 src/main/scala/org/openapitools/client/api/UserApi.scala
 src/main/scala/org/openapitools/client/core/DateSerializers.scala
 src/main/scala/org/openapitools/client/core/JsonSupport.scala
-src/main/scala/org/openapitools/client/core/credentials.scala
 src/main/scala/org/openapitools/client/model/ApiResponse.scala
 src/main/scala/org/openapitools/client/model/Category.scala
 src/main/scala/org/openapitools/client/model/InlineObject.scala
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
index 8e9be2c3795..acbee3036fd 100644
--- 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
@@ -28,7 +28,8 @@ class PetApi(baseUrl: String = "http://petstore.swagger.io/v2") {
    * 
    * @param pet Pet object that needs to be added to the store
    */
-  def addPet(pet: Pet): Request[Either[ResponseError[Exception], Pet], Nothing] =
+  def addPet(pet: Pet
+): Request[Either[ResponseError[Exception], Pet], Nothing] =
     basicRequest
       .method(Method.POST, uri"$baseUrl/pet")
       .contentType("application/json")
@@ -42,7 +43,8 @@ class PetApi(baseUrl: String = "http://petstore.swagger.io/v2") {
    * @param petId Pet id to delete
    * @param apiKey 
    */
-  def deletePet(petId: Long, apiKey: Option[String] = None): Request[Either[ResponseError[Exception], Unit], Nothing] =
+  def deletePet(petId: Long, apiKey: Option[String] = None
+): Request[Either[ResponseError[Exception], Unit], Nothing] =
     basicRequest
       .method(Method.DELETE, uri"$baseUrl/pet/${petId}")
       .contentType("application/json")
@@ -58,7 +60,8 @@ class PetApi(baseUrl: String = "http://petstore.swagger.io/v2") {
    * 
    * @param status Status values that need to be considered for filter
    */
-  def findPetsByStatus(status: Seq[String]): Request[Either[ResponseError[Exception], Seq[Pet]], Nothing] =
+  def findPetsByStatus(status: Seq[String]
+): Request[Either[ResponseError[Exception], Seq[Pet]], Nothing] =
     basicRequest
       .method(Method.GET, uri"$baseUrl/pet/findByStatus?status=$status")
       .contentType("application/json")
@@ -73,7 +76,8 @@ class PetApi(baseUrl: String = "http://petstore.swagger.io/v2") {
    * 
    * @param tags Tags to filter by
    */
-  def findPetsByTags(tags: Seq[String]): Request[Either[ResponseError[Exception], Seq[Pet]], Nothing] =
+  def findPetsByTags(tags: Seq[String]
+): Request[Either[ResponseError[Exception], Seq[Pet]], Nothing] =
     basicRequest
       .method(Method.GET, uri"$baseUrl/pet/findByTags?tags=$tags")
       .contentType("application/json")
@@ -92,11 +96,12 @@ class PetApi(baseUrl: String = "http://petstore.swagger.io/v2") {
    * 
    * @param petId ID of pet to return
    */
-  def getPetById(petId: Long)(implicit apiKey: ApiKeyValue): Request[Either[ResponseError[Exception], Pet], Nothing] =
+  def getPetById(petId: Long, apiKey: String
+): Request[Either[ResponseError[Exception], Pet], Nothing] =
     basicRequest
       .method(Method.GET, uri"$baseUrl/pet/${petId}")
       .contentType("application/json")
-      .header("api_key", apiKey.value)
+      .header("api_key", apiKey)
       .response(asJson[Pet])
 
   /**
@@ -108,7 +113,8 @@ class PetApi(baseUrl: String = "http://petstore.swagger.io/v2") {
    * 
    * @param pet Pet object that needs to be added to the store
    */
-  def updatePet(pet: Pet): Request[Either[ResponseError[Exception], Pet], Nothing] =
+  def updatePet(pet: Pet
+): Request[Either[ResponseError[Exception], Pet], Nothing] =
     basicRequest
       .method(Method.PUT, uri"$baseUrl/pet")
       .contentType("application/json")
@@ -123,7 +129,8 @@ class PetApi(baseUrl: String = "http://petstore.swagger.io/v2") {
    * @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): Request[Either[ResponseError[Exception], Unit], Nothing] =
+  def updatePetWithForm(petId: Long, name: Option[String] = None, status: Option[String] = None
+): Request[Either[ResponseError[Exception], Unit], Nothing] =
     basicRequest
       .method(Method.POST, uri"$baseUrl/pet/${petId}")
       .contentType("application/x-www-form-urlencoded")
@@ -141,7 +148,8 @@ class PetApi(baseUrl: String = "http://petstore.swagger.io/v2") {
    * @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): Request[Either[ResponseError[Exception], ApiResponse], Nothing] =
+  def uploadFile(petId: Long, additionalMetadata: Option[String] = None, file: Option[File] = None
+): Request[Either[ResponseError[Exception], ApiResponse], Nothing] =
     basicRequest
       .method(Method.POST, uri"$baseUrl/pet/${petId}/uploadImage")
       .contentType("multipart/form-data")
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
index 7ddba54d894..386f0af046a 100644
--- 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
@@ -1,14 +1,14 @@
 /**
- * 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.
- */
+  * 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
@@ -20,60 +20,68 @@ import sttp.model.Method
 class StoreApi(baseUrl: String = "http://petstore.swagger.io/v2") {
 
   /**
-   * 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): Request[Either[ResponseError[Exception], Unit], Nothing] =
+    * 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
+  ): Request[Either[ResponseError[Exception], Unit], Nothing] =
     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): Request[Either[ResponseError[Exception], Map[String, Int]], Nothing] =
+    * 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(
+    apiKey: String
+  ): Request[Either[ResponseError[Exception], Map[String, Int]], Nothing] =
     basicRequest
       .method(Method.GET, uri"$baseUrl/store/inventory")
       .contentType("application/json")
-      .header("api_key", apiKey.value)
+      .header("api_key", apiKey)
       .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): Request[Either[ResponseError[Exception], Order], Nothing] =
+    * 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
+  ): Request[Either[ResponseError[Exception], Order], Nothing] =
     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): Request[Either[ResponseError[Exception], Order], Nothing] =
+    * Expected answers:
+    *   code 200 : Order (successful operation)
+    *   code 400 :  (Invalid Order)
+    *
+    * @param order order placed for purchasing the pet
+    */
+  def placeOrder(
+    order: Order
+  ): Request[Either[ResponseError[Exception], Order], Nothing] =
     basicRequest
       .method(Method.POST, uri"$baseUrl/store/order")
       .contentType("application/json")
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
index 058925130cc..cb76dd7d008 100644
--- 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
@@ -30,11 +30,12 @@ class UserApi(baseUrl: String = "http://petstore.swagger.io/v2") {
    * 
    * @param user Created user object
    */
-  def createUser(user: User)(implicit apiKey: ApiKeyValue): Request[Either[ResponseError[Exception], Unit], Nothing] =
+  def createUser(user: User, apiKey: String
+): Request[Either[ResponseError[Exception], Unit], Nothing] =
     basicRequest
       .method(Method.POST, uri"$baseUrl/user")
       .contentType("application/json")
-      .header("api_key", apiKey.value)
+      .header("api_key", apiKey)
       .body(user)
       .response(asJson[Unit])
 
@@ -47,11 +48,12 @@ class UserApi(baseUrl: String = "http://petstore.swagger.io/v2") {
    * 
    * @param user List of user object
    */
-  def createUsersWithArrayInput(user: Seq[User])(implicit apiKey: ApiKeyValue): Request[Either[ResponseError[Exception], Unit], Nothing] =
+  def createUsersWithArrayInput(user: Seq[User], apiKey: String
+): Request[Either[ResponseError[Exception], Unit], Nothing] =
     basicRequest
       .method(Method.POST, uri"$baseUrl/user/createWithArray")
       .contentType("application/json")
-      .header("api_key", apiKey.value)
+      .header("api_key", apiKey)
       .body(user)
       .response(asJson[Unit])
 
@@ -64,11 +66,12 @@ class UserApi(baseUrl: String = "http://petstore.swagger.io/v2") {
    * 
    * @param user List of user object
    */
-  def createUsersWithListInput(user: Seq[User])(implicit apiKey: ApiKeyValue): Request[Either[ResponseError[Exception], Unit], Nothing] =
+  def createUsersWithListInput(user: Seq[User], apiKey: String
+): Request[Either[ResponseError[Exception], Unit], Nothing] =
     basicRequest
       .method(Method.POST, uri"$baseUrl/user/createWithList")
       .contentType("application/json")
-      .header("api_key", apiKey.value)
+      .header("api_key", apiKey)
       .body(user)
       .response(asJson[Unit])
 
@@ -84,11 +87,12 @@ class UserApi(baseUrl: String = "http://petstore.swagger.io/v2") {
    * 
    * @param username The name that needs to be deleted
    */
-  def deleteUser(username: String)(implicit apiKey: ApiKeyValue): Request[Either[ResponseError[Exception], Unit], Nothing] =
+  def deleteUser(username: String, apiKey: String
+): Request[Either[ResponseError[Exception], Unit], Nothing] =
     basicRequest
       .method(Method.DELETE, uri"$baseUrl/user/${username}")
       .contentType("application/json")
-      .header("api_key", apiKey.value)
+      .header("api_key", apiKey)
       .response(asJson[Unit])
 
   /**
@@ -99,7 +103,8 @@ class UserApi(baseUrl: String = "http://petstore.swagger.io/v2") {
    * 
    * @param username The name that needs to be fetched. Use user1 for testing.
    */
-  def getUserByName(username: String): Request[Either[ResponseError[Exception], User], Nothing] =
+  def getUserByName(username: String
+): Request[Either[ResponseError[Exception], User], Nothing] =
     basicRequest
       .method(Method.GET, uri"$baseUrl/user/${username}")
       .contentType("application/json")
@@ -117,7 +122,8 @@ class UserApi(baseUrl: String = "http://petstore.swagger.io/v2") {
    * @param username The user name for login
    * @param password The password for login in clear text
    */
-  def loginUser(username: String, password: String): Request[Either[ResponseError[Exception], String], Nothing] =
+  def loginUser(username: String, password: String
+): Request[Either[ResponseError[Exception], String], Nothing] =
     basicRequest
       .method(Method.GET, uri"$baseUrl/user/login?username=$username&password=$password")
       .contentType("application/json")
@@ -130,11 +136,12 @@ class UserApi(baseUrl: String = "http://petstore.swagger.io/v2") {
    * Available security schemes:
    *   api_key (apiKey)
    */
-  def logoutUser()(implicit apiKey: ApiKeyValue): Request[Either[ResponseError[Exception], Unit], Nothing] =
+  def logoutUser(apiKey: String
+): Request[Either[ResponseError[Exception], Unit], Nothing] =
     basicRequest
       .method(Method.GET, uri"$baseUrl/user/logout")
       .contentType("application/json")
-      .header("api_key", apiKey.value)
+      .header("api_key", apiKey)
       .response(asJson[Unit])
 
   /**
@@ -150,11 +157,12 @@ class UserApi(baseUrl: String = "http://petstore.swagger.io/v2") {
    * @param username name that need to be deleted
    * @param user Updated user object
    */
-  def updateUser(username: String, user: User)(implicit apiKey: ApiKeyValue): Request[Either[ResponseError[Exception], Unit], Nothing] =
+  def updateUser(username: String, user: User, apiKey: String
+): Request[Either[ResponseError[Exception], Unit], Nothing] =
     basicRequest
       .method(Method.PUT, uri"$baseUrl/user/${username}")
       .contentType("application/json")
-      .header("api_key", apiKey.value)
+      .header("api_key", apiKey)
       .body(user)
       .response(asJson[Unit])
 
-- 
GitLab


From 4a5ff2791d74c147eee0437db0f08422890edcbd Mon Sep 17 00:00:00 2001
From: ghostbuster91 <kghost0@gmail.com>
Date: Wed, 10 Jun 2020 14:12:55 +0200
Subject: [PATCH 26/38] Put auth params first

---
 .../main/resources/scala-sttp/api.mustache    |   1 -
 .../scala-sttp/methodParameters.mustache      |   2 +-
 .../org/openapitools/client/api/PetApi.scala  |   3 +-
 .../openapitools/client/api/StoreApi.scala    | 103 +++++++++---------
 .../org/openapitools/client/api/UserApi.scala |  13 +--
 5 files changed, 57 insertions(+), 65 deletions(-)

diff --git a/modules/openapi-generator/src/main/resources/scala-sttp/api.mustache b/modules/openapi-generator/src/main/resources/scala-sttp/api.mustache
index ebb209c2422..de7d65f24e9 100644
--- a/modules/openapi-generator/src/main/resources/scala-sttp/api.mustache
+++ b/modules/openapi-generator/src/main/resources/scala-sttp/api.mustache
@@ -4,7 +4,6 @@ package {{package}}
 {{#imports}}
 import {{import}}
 {{/imports}}
-import {{invokerPackage}}._
 import {{invokerPackage}}.JsonSupport._
 import sttp.client._
 import sttp.model.Method
diff --git a/modules/openapi-generator/src/main/resources/scala-sttp/methodParameters.mustache b/modules/openapi-generator/src/main/resources/scala-sttp/methodParameters.mustache
index 88d0e0d35fb..84bfa581861 100644
--- a/modules/openapi-generator/src/main/resources/scala-sttp/methodParameters.mustache
+++ b/modules/openapi-generator/src/main/resources/scala-sttp/methodParameters.mustache
@@ -1 +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}}{{#allParams.0}}, {{/allParams.0}}{{#authMethods}}{{#isApiKey}}apiKey: String{{/isApiKey}}{{#isBasic}}{{#isBasicBasic}}username: String, password: String{{/isBasicBasic}}{{#isBasicBearer}}bearerToken: String{{/isBasicBearer}}{{/isBasic}}{{#hasMore}}, {{/hasMore}}{{/authMethods}}{{/authMethods.0}}
+{{#authMethods.0}}{{#authMethods}}{{#isApiKey}}apiKey: String{{/isApiKey}}{{#isBasic}}{{#isBasicBasic}}username: String, password: String{{/isBasicBasic}}{{#isBasicBearer}}bearerToken: String{{/isBasicBearer}}{{/isBasic}}{{#hasMore}}, {{/hasMore}}{{/authMethods}})({{/authMethods.0}}{{#allParams}}{{paramName}}: {{#required}}{{dataType}}{{/required}}{{^required}}{{#isContainer}}{{dataType}}{{/isContainer}}{{^isContainer}}Option[{{dataType}}]{{/isContainer}}{{/required}}{{^defaultValue}}{{^required}}{{^isContainer}} = None{{/isContainer}}{{/required}}{{/defaultValue}}{{#hasMore}}, {{/hasMore}}{{/allParams}}
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
index acbee3036fd..bbebc500a1c 100644
--- 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
@@ -14,7 +14,6 @@ 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 org.openapitools.client.core.JsonSupport._
 import sttp.client._
 import sttp.model.Method
@@ -96,7 +95,7 @@ class PetApi(baseUrl: String = "http://petstore.swagger.io/v2") {
    * 
    * @param petId ID of pet to return
    */
-  def getPetById(petId: Long, apiKey: String
+  def getPetById(apiKey: String)(petId: Long
 ): Request[Either[ResponseError[Exception], Pet], Nothing] =
     basicRequest
       .method(Method.GET, uri"$baseUrl/pet/${petId}")
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
index 386f0af046a..6534c77c8bd 100644
--- 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
@@ -1,18 +1,17 @@
 /**
-  * 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.
-  */
+ * 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 org.openapitools.client.core.JsonSupport._
 import sttp.client._
 import sttp.model.Method
@@ -20,34 +19,32 @@ import sttp.model.Method
 class StoreApi(baseUrl: String = "http://petstore.swagger.io/v2") {
 
   /**
-    * 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
-  ): Request[Either[ResponseError[Exception], Unit], Nothing] =
+   * 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
+): Request[Either[ResponseError[Exception], Unit], Nothing] =
     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(
-    apiKey: String
-  ): Request[Either[ResponseError[Exception], Map[String, Int]], Nothing] =
+   * 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(apiKey: String)(
+): Request[Either[ResponseError[Exception], Map[String, Int]], Nothing] =
     basicRequest
       .method(Method.GET, uri"$baseUrl/store/inventory")
       .contentType("application/json")
@@ -55,33 +52,31 @@ class StoreApi(baseUrl: String = "http://petstore.swagger.io/v2") {
       .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
-  ): Request[Either[ResponseError[Exception], Order], Nothing] =
+   * 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
+): Request[Either[ResponseError[Exception], Order], Nothing] =
     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
-  ): Request[Either[ResponseError[Exception], Order], Nothing] =
+   * Expected answers:
+   *   code 200 : Order (successful operation)
+   *   code 400 :  (Invalid Order)
+   * 
+   * @param order order placed for purchasing the pet
+   */
+  def placeOrder(order: Order
+): Request[Either[ResponseError[Exception], Order], Nothing] =
     basicRequest
       .method(Method.POST, uri"$baseUrl/store/order")
       .contentType("application/json")
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
index cb76dd7d008..ec6bae552a4 100644
--- 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
@@ -12,7 +12,6 @@
 package org.openapitools.client.api
 
 import org.openapitools.client.model.User
-import org.openapitools.client.core._
 import org.openapitools.client.core.JsonSupport._
 import sttp.client._
 import sttp.model.Method
@@ -30,7 +29,7 @@ class UserApi(baseUrl: String = "http://petstore.swagger.io/v2") {
    * 
    * @param user Created user object
    */
-  def createUser(user: User, apiKey: String
+  def createUser(apiKey: String)(user: User
 ): Request[Either[ResponseError[Exception], Unit], Nothing] =
     basicRequest
       .method(Method.POST, uri"$baseUrl/user")
@@ -48,7 +47,7 @@ class UserApi(baseUrl: String = "http://petstore.swagger.io/v2") {
    * 
    * @param user List of user object
    */
-  def createUsersWithArrayInput(user: Seq[User], apiKey: String
+  def createUsersWithArrayInput(apiKey: String)(user: Seq[User]
 ): Request[Either[ResponseError[Exception], Unit], Nothing] =
     basicRequest
       .method(Method.POST, uri"$baseUrl/user/createWithArray")
@@ -66,7 +65,7 @@ class UserApi(baseUrl: String = "http://petstore.swagger.io/v2") {
    * 
    * @param user List of user object
    */
-  def createUsersWithListInput(user: Seq[User], apiKey: String
+  def createUsersWithListInput(apiKey: String)(user: Seq[User]
 ): Request[Either[ResponseError[Exception], Unit], Nothing] =
     basicRequest
       .method(Method.POST, uri"$baseUrl/user/createWithList")
@@ -87,7 +86,7 @@ class UserApi(baseUrl: String = "http://petstore.swagger.io/v2") {
    * 
    * @param username The name that needs to be deleted
    */
-  def deleteUser(username: String, apiKey: String
+  def deleteUser(apiKey: String)(username: String
 ): Request[Either[ResponseError[Exception], Unit], Nothing] =
     basicRequest
       .method(Method.DELETE, uri"$baseUrl/user/${username}")
@@ -136,7 +135,7 @@ class UserApi(baseUrl: String = "http://petstore.swagger.io/v2") {
    * Available security schemes:
    *   api_key (apiKey)
    */
-  def logoutUser(apiKey: String
+  def logoutUser(apiKey: String)(
 ): Request[Either[ResponseError[Exception], Unit], Nothing] =
     basicRequest
       .method(Method.GET, uri"$baseUrl/user/logout")
@@ -157,7 +156,7 @@ class UserApi(baseUrl: String = "http://petstore.swagger.io/v2") {
    * @param username name that need to be deleted
    * @param user Updated user object
    */
-  def updateUser(username: String, user: User, apiKey: String
+  def updateUser(apiKey: String)(username: String, user: User
 ): Request[Either[ResponseError[Exception], Unit], Nothing] =
     basicRequest
       .method(Method.PUT, uri"$baseUrl/user/${username}")
-- 
GitLab


From e2df636df394c713d68b9223d960999d58bd2bc7 Mon Sep 17 00:00:00 2001
From: ghostbuster91 <kghost0@gmail.com>
Date: Tue, 16 Jun 2020 14:32:12 +0200
Subject: [PATCH 27/38] [Sttp] SeparateErrorChannel is true by default

---
 docs/generators/scala-sttp.md | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/docs/generators/scala-sttp.md b/docs/generators/scala-sttp.md
index c8016761aa6..ad884845180 100644
--- a/docs/generators/scala-sttp.md
+++ b/docs/generators/scala-sttp.md
@@ -13,7 +13,7 @@ sidebar_label: scala-sttp
 |json4sVersion|Only if jsonLibrary was set to json4s. Allows to override default json4s version.|3.6.8
 |circeVersion|Only if jsonLibrary was set to circe. Allows to override default circe version.|0.13.0 
 |jsonLibrary|Option. Json library to use|<dl><dt>**json4s**</dt>https://github.com/json4s/json4s<dt>**circe**</dt><dd>https://github.com/circe/circe</dd></dl>|json4s|
-|separateErrorChannel| Option. Whether to return response as `F[Either[ResponseError[ErrorType], ReturnType]]]` or to flatten response's error raising them through enclosing monad (`F[ReturnType]`).|false
+|separateErrorChannel| Option. Whether to return response as `F[Either[ResponseError[ErrorType], ReturnType]]]` or to flatten response's error raising them through enclosing monad (`F[ReturnType]`).|true
 |disallowAdditionalPropertiesIfNotPresent|Specify the behavior when the 'additionalProperties' keyword is not present in the OAS document. If false: the 'additionalProperties' implementation is compliant with the OAS and JSON schema specifications. If true: when the 'additionalProperties' keyword is not present in a schema, the value of 'additionalProperties' is set to false, i.e. no additional properties are allowed. Note: this mode is not compliant with the JSON schema specification. This is the original openapi-generator behavior.This setting is currently ignored for OAS 2.0 documents:  1) When the 'additionalProperties' keyword is not present in a 2.0 schema, additional properties are NOT allowed.  2) Boolean values of the 'additionalProperties' keyword are ignored. It's as if additional properties are NOT allowed.Note: the root cause are issues #1369 and #1371, which must be resolved in the swagger-parser project.|<dl><dt>**false**</dt><dd>The 'additionalProperties' implementation is compliant with the OAS and JSON schema specifications.</dd><dt>**true**</dt><dd>when the 'additionalProperties' keyword is not present in a schema, the value of 'additionalProperties' is automatically set to false, i.e. no additional properties are allowed. Note: this mode is not compliant with the JSON schema specification. This is the original openapi-generator behavior.</dd></dl>|true|
 |ensureUniqueParams|Whether to ensure parameter names are unique in an operation (rename parameters that are not).| |true|
 |legacyDiscriminatorBehavior|This flag is used by OpenAPITools codegen to influence the processing of the discriminator attribute in OpenAPI documents. This flag has no impact if the OAS document does not use the discriminator attribute. The default value of this flag is set in each language-specific code generator (e.g. Python, Java, go...)using the method toModelName. Note to developers supporting a language generator in OpenAPITools; to fully support the discriminator attribute as defined in the OAS specification 3.x, language generators should set this flag to true by default; however this requires updating the mustache templates to generate a language-specific discriminator lookup function that iterates over {{#mappedModels}} and does not iterate over {{children}}, {{#anyOf}}, or {{#oneOf}}.|<dl><dt>**true**</dt><dd>The mapping in the discriminator includes descendent schemas that allOf inherit from self and the discriminator mapping schemas in the OAS document.</dd><dt>**false**</dt><dd>The mapping in the discriminator includes any descendent schemas that allOf inherit from self, any oneOf schemas, any anyOf schemas, any x-discriminator-values, and the discriminator mapping schemas in the OAS document AND Codegen validates that oneOf and anyOf schemas contain the required discriminator and throws an error if the discriminator is missing.</dd></dl>|true|
-- 
GitLab


From b3017bb838a59e9c698f4a130bae6f41e01063ba Mon Sep 17 00:00:00 2001
From: ghostbuster91 <kghost0@gmail.com>
Date: Tue, 16 Jun 2020 14:32:59 +0200
Subject: [PATCH 28/38] [Sttp] Simplify generated build.sbt

---
 .../src/main/resources/scala-sttp/build.sbt.mustache          | 4 ----
 1 file changed, 4 deletions(-)

diff --git a/modules/openapi-generator/src/main/resources/scala-sttp/build.sbt.mustache b/modules/openapi-generator/src/main/resources/scala-sttp/build.sbt.mustache
index 4fcde1bb28c..d16d5bd6822 100644
--- a/modules/openapi-generator/src/main/resources/scala-sttp/build.sbt.mustache
+++ b/modules/openapi-generator/src/main/resources/scala-sttp/build.sbt.mustache
@@ -4,8 +4,6 @@ organization := "{{groupId}}"
 
 scalaVersion := "2.13.2"
 
-crossScalaVersions := Seq(scalaVersion.value, "2.12.10", "2.11.12")
-
 libraryDependencies ++= Seq(
   "com.softwaremill.sttp.client" %% "core" % "{{sttpClientVersion}}",
 {{#joda}}
@@ -28,5 +26,3 @@ scalacOptions := Seq(
   "-deprecation",
   "-feature"
 )
-
-publishArtifact in (Compile, packageDoc) := false
-- 
GitLab


From 86150cb88f5bdbb39a5d38fee0fb7fb8456c5861 Mon Sep 17 00:00:00 2001
From: ghostbuster91 <kghost0@gmail.com>
Date: Tue, 16 Jun 2020 14:42:14 +0200
Subject: [PATCH 29/38] [Sttp] Regenerate project

---
 samples/client/petstore/scala-sttp/build.sbt | 4 ----
 1 file changed, 4 deletions(-)

diff --git a/samples/client/petstore/scala-sttp/build.sbt b/samples/client/petstore/scala-sttp/build.sbt
index e9dd062cdcb..d56dc8621bf 100644
--- a/samples/client/petstore/scala-sttp/build.sbt
+++ b/samples/client/petstore/scala-sttp/build.sbt
@@ -4,8 +4,6 @@ organization := "org.openapitools"
 
 scalaVersion := "2.13.2"
 
-crossScalaVersions := Seq(scalaVersion.value, "2.12.10", "2.11.12")
-
 libraryDependencies ++= Seq(
   "com.softwaremill.sttp.client" %% "core" % "2.1.5",
   "com.softwaremill.sttp.client" %% "json4s" % "2.1.5",
@@ -17,5 +15,3 @@ scalacOptions := Seq(
   "-deprecation",
   "-feature"
 )
-
-publishArtifact in (Compile, packageDoc) := false
-- 
GitLab


From 4588362969fa47fa2aa9e126fbb7a36e3af860ce Mon Sep 17 00:00:00 2001
From: ghostbuster91 <kghost0@gmail.com>
Date: Tue, 16 Jun 2020 15:38:21 +0200
Subject: [PATCH 30/38] [Sttp] Update default version to 2.2.0

---
 docs/generators/scala-sttp.md                                   | 2 +-
 .../openapitools/codegen/languages/ScalaSttpClientCodegen.java  | 2 +-
 2 files changed, 2 insertions(+), 2 deletions(-)

diff --git a/docs/generators/scala-sttp.md b/docs/generators/scala-sttp.md
index ad884845180..ab09d61bac4 100644
--- a/docs/generators/scala-sttp.md
+++ b/docs/generators/scala-sttp.md
@@ -7,7 +7,7 @@ sidebar_label: scala-sttp
 | ------ | ----------- | ------ | ------- |
 |allowUnicodeIdentifiers|boolean, toggles whether unicode identifiers are allowed in names or not, default is false| |false|
 |apiPackage|package for generated api classes| |null|
-|sttpClientVersion|Option. Allows to override default version of sttp client library.|2.1.5
+|sttpClientVersion|Option. Allows to override default version of sttp client library. Minimal version required for this project to compile is 2.2.0 |2.2.0
 |dateLibrary|Option. Date library to use|<dl><dt>**joda**</dt><dd>Joda (for legacy app)</dd><dt>**java8**</dt><dd>Java 8 native JSR310 (prefered for JDK 1.8+)</dd></dl>|java8|
 |jodaTimeVersion|Only if dateLibrary was set to joda. Allows to override default jodatime version.|2.10.6
 |json4sVersion|Only if jsonLibrary was set to json4s. Allows to override default json4s version.|3.6.8
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
index bb1fdf42df8..10d8e1faf73 100644
--- 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
@@ -42,7 +42,7 @@ import static org.openapitools.codegen.utils.StringUtils.camelize;
 
 public class ScalaSttpClientCodegen extends AbstractScalaCodegen implements CodegenConfig {
     private static final StringProperty STTP_CLIENT_VERSION = new StringProperty("sttpClientVersion", "The version of " +
-            "sttp client", "2.1.5");
+            "sttp client", "2.2.0");
     private static final BooleanProperty USE_SEPARATE_ERROR_CHANNEL = new BooleanProperty("separateErrorChannel",
             "Whether to return response as " +
                     "F[Either[ResponseError[ErrorType], ReturnType]]] or to flatten " +
-- 
GitLab


From b572673b70b7076f67ac072c771f629ffbc57106 Mon Sep 17 00:00:00 2001
From: ghostbuster91 <kghost0@gmail.com>
Date: Tue, 16 Jun 2020 16:03:14 +0200
Subject: [PATCH 31/38] Regenerate petstore sample

---
 samples/client/petstore/scala-sttp/build.sbt | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/samples/client/petstore/scala-sttp/build.sbt b/samples/client/petstore/scala-sttp/build.sbt
index d56dc8621bf..9cd82854e8c 100644
--- a/samples/client/petstore/scala-sttp/build.sbt
+++ b/samples/client/petstore/scala-sttp/build.sbt
@@ -5,8 +5,8 @@ organization := "org.openapitools"
 scalaVersion := "2.13.2"
 
 libraryDependencies ++= Seq(
-  "com.softwaremill.sttp.client" %% "core" % "2.1.5",
-  "com.softwaremill.sttp.client" %% "json4s" % "2.1.5",
+  "com.softwaremill.sttp.client" %% "core" % "2.2.0",
+  "com.softwaremill.sttp.client" %% "json4s" % "2.2.0",
   "org.json4s" %% "json4s-jackson" % "3.6.8"
 )
 
-- 
GitLab


From 91dd9b036ebc6b53efacdc32d7c16a89ccb342f6 Mon Sep 17 00:00:00 2001
From: ghostbuster91 <kghost0@gmail.com>
Date: Tue, 23 Jun 2020 08:15:21 +0200
Subject: [PATCH 32/38] Restore cross-compilation to scala 2.12

---
 .../src/main/resources/scala-sttp/build.sbt.mustache             | 1 +
 samples/client/petstore/scala-sttp/build.sbt                     | 1 +
 2 files changed, 2 insertions(+)

diff --git a/modules/openapi-generator/src/main/resources/scala-sttp/build.sbt.mustache b/modules/openapi-generator/src/main/resources/scala-sttp/build.sbt.mustache
index d16d5bd6822..a20ba532f44 100644
--- a/modules/openapi-generator/src/main/resources/scala-sttp/build.sbt.mustache
+++ b/modules/openapi-generator/src/main/resources/scala-sttp/build.sbt.mustache
@@ -3,6 +3,7 @@ name := "{{artifactId}}"
 organization := "{{groupId}}"
 
 scalaVersion := "2.13.2"
+crossScalaVersions := Seq(scalaVersion.value, "2.12.10")
 
 libraryDependencies ++= Seq(
   "com.softwaremill.sttp.client" %% "core" % "{{sttpClientVersion}}",
diff --git a/samples/client/petstore/scala-sttp/build.sbt b/samples/client/petstore/scala-sttp/build.sbt
index 9cd82854e8c..e7d77cdd2db 100644
--- a/samples/client/petstore/scala-sttp/build.sbt
+++ b/samples/client/petstore/scala-sttp/build.sbt
@@ -3,6 +3,7 @@ name := "scala-sttp-petstore"
 organization := "org.openapitools"
 
 scalaVersion := "2.13.2"
+crossScalaVersions := Seq(scalaVersion.value, "2.12.10")
 
 libraryDependencies ++= Seq(
   "com.softwaremill.sttp.client" %% "core" % "2.2.0",
-- 
GitLab


From 9242bc4b661686d554786e65a671deb41ae3a4d7 Mon Sep 17 00:00:00 2001
From: ghostbuster91 <kghost0@gmail.com>
Date: Tue, 23 Jun 2020 08:30:30 +0200
Subject: [PATCH 33/38] Restore syntax with companion object for api
 definitions

---
 .../src/main/resources/scala-sttp/api.mustache             | 7 ++++++-
 .../main/scala/org/openapitools/client/api/PetApi.scala    | 7 ++++++-
 .../main/scala/org/openapitools/client/api/StoreApi.scala  | 7 ++++++-
 .../main/scala/org/openapitools/client/api/UserApi.scala   | 7 ++++++-
 4 files changed, 24 insertions(+), 4 deletions(-)

diff --git a/modules/openapi-generator/src/main/resources/scala-sttp/api.mustache b/modules/openapi-generator/src/main/resources/scala-sttp/api.mustache
index de7d65f24e9..e67b67018c5 100644
--- a/modules/openapi-generator/src/main/resources/scala-sttp/api.mustache
+++ b/modules/openapi-generator/src/main/resources/scala-sttp/api.mustache
@@ -9,7 +9,12 @@ import sttp.client._
 import sttp.model.Method
 
 {{#operations}}
-class {{classname}}(baseUrl: String = "{{{basePath}}}") {
+object {{classname}} {
+
+def apply(baseUrl: String = "{{{basePath}}}") = new {{classname}}(baseUrl)
+}
+
+class {{classname}}(baseUrl: String) {
 
 {{#operation}}
 {{#javadocRenderer}}
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
index bbebc500a1c..034cceb63cc 100644
--- 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
@@ -18,7 +18,12 @@ import org.openapitools.client.core.JsonSupport._
 import sttp.client._
 import sttp.model.Method
 
-class PetApi(baseUrl: String = "http://petstore.swagger.io/v2") {
+object PetApi {
+
+def apply(baseUrl: String = "http://petstore.swagger.io/v2") = new PetApi(baseUrl)
+}
+
+class PetApi(baseUrl: String) {
 
   /**
    * Expected answers:
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
index 6534c77c8bd..e6ffcaae629 100644
--- 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
@@ -16,7 +16,12 @@ import org.openapitools.client.core.JsonSupport._
 import sttp.client._
 import sttp.model.Method
 
-class StoreApi(baseUrl: String = "http://petstore.swagger.io/v2") {
+object StoreApi {
+
+def apply(baseUrl: String = "http://petstore.swagger.io/v2") = new StoreApi(baseUrl)
+}
+
+class StoreApi(baseUrl: String) {
 
   /**
    * For valid response try integer IDs with value < 1000. Anything above 1000 or nonintegers will generate API errors
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
index ec6bae552a4..fd3b82392b8 100644
--- 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
@@ -16,7 +16,12 @@ import org.openapitools.client.core.JsonSupport._
 import sttp.client._
 import sttp.model.Method
 
-class UserApi(baseUrl: String = "http://petstore.swagger.io/v2") {
+object UserApi {
+
+def apply(baseUrl: String = "http://petstore.swagger.io/v2") = new UserApi(baseUrl)
+}
+
+class UserApi(baseUrl: String) {
 
   /**
    * This can only be done by the logged in user.
-- 
GitLab


From de82caf10a7b2192a179ebb3354ded82425f3751 Mon Sep 17 00:00:00 2001
From: ghostbuster91 <kghost0@gmail.com>
Date: Tue, 23 Jun 2020 08:43:03 +0200
Subject: [PATCH 34/38] Remove specifying reservedWords as it was already
 specified in upper class

---
 .../codegen/languages/ScalaSttpClientCodegen.java        | 9 ---------
 1 file changed, 9 deletions(-)

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
index 10d8e1faf73..2c97530e2e5 100644
--- 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
@@ -118,15 +118,6 @@ public class ScalaSttpClientCodegen extends AbstractScalaCodegen implements Code
         modelPackage = mainPackage + ".model";
         invokerPackage = mainPackage + ".core";
 
-        setReservedWordsLowerCase(
-                Arrays.asList(
-                        "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", "try", "true", "type", "val", "var", "while", "with", "yield")
-        );
-
         additionalProperties.put(CodegenConstants.GROUP_ID, groupId);
         additionalProperties.put(CodegenConstants.ARTIFACT_ID, artifactId);
         additionalProperties.put(CodegenConstants.ARTIFACT_VERSION, artifactVersion);
-- 
GitLab


From d868eda1df48acccb0b420cec437068d6ade472c Mon Sep 17 00:00:00 2001
From: ghostbuster91 <kghost0@gmail.com>
Date: Tue, 23 Jun 2020 10:32:43 +0200
Subject: [PATCH 35/38] Refactor mainPackageProperty and add tests for it

---
 .../languages/ScalaSttpClientCodegen.java     | 101 +++++++++---------
 .../scala/SttpBooleanPropertyTest.java        |  29 +++++
 .../scala/SttpJsonLibraryPropertyTest.java    |  39 +++++++
 .../scala/SttpPackagePropertyTest.java        |  59 ++++++++++
 .../codegen/scala/SttpStringPropertyTest.java |  30 ++++++
 5 files changed, 209 insertions(+), 49 deletions(-)
 create mode 100644 modules/openapi-generator/src/test/java/org/openapitools/codegen/scala/SttpBooleanPropertyTest.java
 create mode 100644 modules/openapi-generator/src/test/java/org/openapitools/codegen/scala/SttpJsonLibraryPropertyTest.java
 create mode 100644 modules/openapi-generator/src/test/java/org/openapitools/codegen/scala/SttpPackagePropertyTest.java
 create mode 100644 modules/openapi-generator/src/test/java/org/openapitools/codegen/scala/SttpStringPropertyTest.java

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
index 2c97530e2e5..4fc1efdd507 100644
--- 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
@@ -55,22 +55,15 @@ public class ScalaSttpClientCodegen extends AbstractScalaCodegen implements Code
             "library", "0.13.0");
     private static final JsonLibraryProperty JSON_LIBRARY_PROPERTY = new JsonLibraryProperty();
 
-    private static final String DEFAULT_PACKAGE_NAME = "org.openapitools.client";
-    private static final MainPackageProperty MAIN_PACKAGE = new MainPackageProperty();
-    private static final StringProperty MODEL_PACKAGE = new StringProperty(CodegenConstants.MODEL_PACKAGE,
-            CodegenConstants.MODEL_PACKAGE_DESC, DEFAULT_PACKAGE_NAME + ".model");
-    private static final StringProperty INVOKER_PACKAGE = new StringProperty(CodegenConstants.INVOKER_PACKAGE,
-            CodegenConstants.MODEL_PACKAGE_DESC, DEFAULT_PACKAGE_NAME + ".core");
-    private static final StringProperty API_PACKAGE = new StringProperty(CodegenConstants.API_PACKAGE,
-            CodegenConstants.API_PACKAGE_DESC, DEFAULT_PACKAGE_NAME + ".api");
-
-    private static final List<Property> properties = Arrays.asList(STTP_CLIENT_VERSION, USE_SEPARATE_ERROR_CHANNEL,
-            JODA_TIME_VERSION, JSON4S_VERSION, CIRCE_VERSION, JSON_LIBRARY_PROPERTY,MAIN_PACKAGE, API_PACKAGE,
-            MODEL_PACKAGE, INVOKER_PACKAGE);
+    public static final String DEFAULT_PACKAGE_NAME = "org.openapitools.client";
+    private static final PackageProperty PACKAGE_PROPERTY = new PackageProperty();
+
+    private static final List<Property<?>> properties = Arrays.asList(
+            STTP_CLIENT_VERSION, USE_SEPARATE_ERROR_CHANNEL, JODA_TIME_VERSION,
+            JSON4S_VERSION, CIRCE_VERSION, JSON_LIBRARY_PROPERTY, PACKAGE_PROPERTY);
 
     private final Logger LOGGER = LoggerFactory.getLogger(ScalaSttpClientCodegen.class);
 
-    protected String mainPackage = "org.openapitools.client";
     protected String groupId = "org.openapitools";
     protected String artifactId = "openapi-client";
     protected String artifactVersion = "1.0.0";
@@ -114,9 +107,6 @@ public class ScalaSttpClientCodegen extends AbstractScalaCodegen implements Code
         modelTemplateFiles.put("model.mustache", ".scala");
         apiTemplateFiles.put("api.mustache", ".scala");
         embeddedTemplateDir = templateDir = "scala-sttp";
-        apiPackage = mainPackage + ".api";
-        modelPackage = mainPackage + ".model";
-        invokerPackage = mainPackage + ".core";
 
         additionalProperties.put(CodegenConstants.GROUP_ID, groupId);
         additionalProperties.put(CodegenConstants.ARTIFACT_ID, artifactId);
@@ -154,16 +144,19 @@ public class ScalaSttpClientCodegen extends AbstractScalaCodegen implements Code
         instantiationTypes.put("array", "ListBuffer");
         instantiationTypes.put("map", "Map");
 
-        properties.forEach(p -> cliOptions.add(p.toCliOption()));
+        properties.stream()
+                .map(Property::toCliOptions)
+                .flatMap(Collection::stream)
+                .forEach(option -> cliOptions.add(option));
     }
 
     @Override
     public void processOpts() {
         super.processOpts();
         properties.forEach(p -> p.updateAdditionalProperties(additionalProperties));
-        invokerPackage = INVOKER_PACKAGE.getValue(additionalProperties);
-        apiPackage = API_PACKAGE.getValue(additionalProperties);
-        modelPackage = MODEL_PACKAGE.getValue(additionalProperties);
+        invokerPackage = PACKAGE_PROPERTY.getInvokerPackage(additionalProperties);
+        apiPackage = PACKAGE_PROPERTY.getApiPackage(additionalProperties);
+        modelPackage = PACKAGE_PROPERTY.getModelPackage(additionalProperties);
 
         supportingFiles.add(new SupportingFile("README.mustache", "", "README.md"));
         supportingFiles.add(new SupportingFile("build.sbt.mustache", "", "build.sbt"));
@@ -315,18 +308,18 @@ public class ScalaSttpClientCodegen extends AbstractScalaCodegen implements Code
         }
     }
 
-    private static abstract class Property<T> {
+    public static abstract class Property<T> {
         final String name;
         final String description;
         final T defaultValue;
 
-        private Property(String name, String description, T defaultValue) {
+        public Property(String name, String description, T defaultValue) {
             this.name = name;
             this.description = description;
             this.defaultValue = defaultValue;
         }
 
-        public abstract CliOption toCliOption();
+        public abstract List<CliOption> toCliOptions();
 
         public abstract void updateAdditionalProperties(Map<String, Object> additionalProperties);
 
@@ -337,14 +330,14 @@ public class ScalaSttpClientCodegen extends AbstractScalaCodegen implements Code
         }
     }
 
-    private static class StringProperty extends Property<String> {
-        private StringProperty(String name, String description, String defaultValue) {
+    public static class StringProperty extends Property<String> {
+        public StringProperty(String name, String description, String defaultValue) {
             super(name, description, defaultValue);
         }
 
         @Override
-        public CliOption toCliOption() {
-            return CliOption.newString(name, description).defaultValue(defaultValue);
+        public List<CliOption> toCliOptions() {
+            return Collections.singletonList(CliOption.newString(name, description).defaultValue(defaultValue));
         }
 
         @Override
@@ -360,14 +353,14 @@ public class ScalaSttpClientCodegen extends AbstractScalaCodegen implements Code
         }
     }
 
-    private static class BooleanProperty extends Property<Boolean> {
-        private BooleanProperty(String name, String description, Boolean defaultValue) {
+    public static class BooleanProperty extends Property<Boolean> {
+        public BooleanProperty(String name, String description, Boolean defaultValue) {
             super(name, description, defaultValue);
         }
 
         @Override
-        public CliOption toCliOption() {
-            return CliOption.newBoolean(name, description, defaultValue);
+        public List<CliOption> toCliOptions() {
+            return Collections.singletonList(CliOption.newBoolean(name, description, defaultValue));
         }
 
         @Override
@@ -382,11 +375,11 @@ public class ScalaSttpClientCodegen extends AbstractScalaCodegen implements Code
         }
     }
 
-    private static class JsonLibraryProperty extends StringProperty {
+    public static class JsonLibraryProperty extends StringProperty {
         private static final String JSON4S = "json4s";
         private static final String CIRCE = "circe";
 
-        private JsonLibraryProperty() {
+        public JsonLibraryProperty() {
             super("jsonLibrary", "Json library to use. Possible values are: json4s and circe.", JSON4S);
         }
 
@@ -405,31 +398,41 @@ public class ScalaSttpClientCodegen extends AbstractScalaCodegen implements Code
         }
     }
 
-    private static class MainPackageProperty extends StringProperty {
+    public static class PackageProperty extends StringProperty {
 
-        private MainPackageProperty() {
+        public PackageProperty() {
             super("mainPackage", "Top-level package name, which defines 'apiPackage', 'modelPackage', " +
                     "'invokerPackage'", DEFAULT_PACKAGE_NAME);
         }
 
         @Override
         public void updateAdditionalProperties(Map<String, Object> additionalProperties) {
-            if (additionalProperties.containsKey(name)) {
-                String mainPackage = getValue(additionalProperties);
-                if (!additionalProperties.containsKey(CodegenConstants.API_PACKAGE)){
-                    String apiPackage = mainPackage + ".api";
-                    additionalProperties.put(CodegenConstants.API_PACKAGE, apiPackage);
-                }
-                if (!additionalProperties.containsKey(CodegenConstants.MODEL_PACKAGE)){
-                    String modelPackage = mainPackage + ".model";
-                    additionalProperties.put(CodegenConstants.MODEL_PACKAGE, modelPackage);
-                }
-                if (!additionalProperties.containsKey(CodegenConstants.INVOKER_PACKAGE)){
-                    String invokerPackage = mainPackage + ".core";
-                    additionalProperties.put(CodegenConstants.INVOKER_PACKAGE, invokerPackage);
-                }
+            String mainPackage = getValue(additionalProperties);
+            if (!additionalProperties.containsKey(CodegenConstants.API_PACKAGE)) {
+                String apiPackage = mainPackage + ".api";
+                additionalProperties.put(CodegenConstants.API_PACKAGE, apiPackage);
+            }
+            if (!additionalProperties.containsKey(CodegenConstants.MODEL_PACKAGE)) {
+                String modelPackage = mainPackage + ".model";
+                additionalProperties.put(CodegenConstants.MODEL_PACKAGE, modelPackage);
+            }
+            if (!additionalProperties.containsKey(CodegenConstants.INVOKER_PACKAGE)) {
+                String invokerPackage = mainPackage + ".core";
+                additionalProperties.put(CodegenConstants.INVOKER_PACKAGE, invokerPackage);
             }
         }
+
+        public String getApiPackage(Map<String, Object> additionalProperties) {
+            return additionalProperties.getOrDefault(CodegenConstants.API_PACKAGE, DEFAULT_PACKAGE_NAME + ".api").toString();
+        }
+
+        public String getModelPackage(Map<String, Object> additionalProperties) {
+            return additionalProperties.getOrDefault(CodegenConstants.MODEL_PACKAGE, DEFAULT_PACKAGE_NAME + ".model").toString();
+        }
+
+        public String getInvokerPackage(Map<String, Object> additionalProperties) {
+            return additionalProperties.getOrDefault(CodegenConstants.INVOKER_PACKAGE, DEFAULT_PACKAGE_NAME + ".core").toString();
+        }
     }
 
     private static abstract class CustomLambda implements Mustache.Lambda {
diff --git a/modules/openapi-generator/src/test/java/org/openapitools/codegen/scala/SttpBooleanPropertyTest.java b/modules/openapi-generator/src/test/java/org/openapitools/codegen/scala/SttpBooleanPropertyTest.java
new file mode 100644
index 00000000000..c500dda7706
--- /dev/null
+++ b/modules/openapi-generator/src/test/java/org/openapitools/codegen/scala/SttpBooleanPropertyTest.java
@@ -0,0 +1,29 @@
+package org.openapitools.codegen.scala;
+
+import org.junit.Assert;
+import org.junit.Test;
+import org.openapitools.codegen.languages.ScalaSttpClientCodegen;
+
+import java.util.HashMap;
+import java.util.Map;
+
+public class SttpBooleanPropertyTest {
+    @Test
+    public void shouldUseDefaultValueIfAdditionalPropertiesAreEmpty() {
+        ScalaSttpClientCodegen.BooleanProperty booleanProperty = new ScalaSttpClientCodegen.BooleanProperty("k1", "desc", false);
+        Map<String, Object> additionalProperties = new HashMap<>();
+        booleanProperty.updateAdditionalProperties(additionalProperties);
+
+        Assert.assertEquals(false, additionalProperties.get("k1"));
+    }
+
+    @Test
+    public void shouldUseGivenValueIfProvided() {
+        ScalaSttpClientCodegen.BooleanProperty booleanProperty = new ScalaSttpClientCodegen.BooleanProperty("k1", "desc", false);
+        Map<String, Object> additionalProperties = new HashMap<>();
+        additionalProperties.put("k1", true);
+        booleanProperty.updateAdditionalProperties(additionalProperties);
+
+        Assert.assertEquals(true, additionalProperties.get("k1"));
+    }
+}
diff --git a/modules/openapi-generator/src/test/java/org/openapitools/codegen/scala/SttpJsonLibraryPropertyTest.java b/modules/openapi-generator/src/test/java/org/openapitools/codegen/scala/SttpJsonLibraryPropertyTest.java
new file mode 100644
index 00000000000..d8473cb8f5d
--- /dev/null
+++ b/modules/openapi-generator/src/test/java/org/openapitools/codegen/scala/SttpJsonLibraryPropertyTest.java
@@ -0,0 +1,39 @@
+package org.openapitools.codegen.scala;
+
+import org.junit.Assert;
+import org.junit.Test;
+import org.openapitools.codegen.languages.ScalaSttpClientCodegen;
+
+import java.util.HashMap;
+import java.util.Map;
+
+public class SttpJsonLibraryPropertyTest {
+    @Test
+    public void shouldUseJson4sByDefault() {
+        ScalaSttpClientCodegen.JsonLibraryProperty property = new ScalaSttpClientCodegen.JsonLibraryProperty();
+        Map<String, Object> additionalProperties = new HashMap<>();
+        property.updateAdditionalProperties(additionalProperties);
+        Assert.assertEquals(true, additionalProperties.get("json4s"));
+        Assert.assertEquals(false, additionalProperties.get("circe"));
+    }
+
+    @Test
+    public void shouldUseJson4sIfExplicitlyAskTo() {
+        ScalaSttpClientCodegen.JsonLibraryProperty property = new ScalaSttpClientCodegen.JsonLibraryProperty();
+        Map<String, Object> additionalProperties = new HashMap<>();
+        additionalProperties.put("jsonLibrary", "json4s");
+        property.updateAdditionalProperties(additionalProperties);
+        Assert.assertEquals(true, additionalProperties.get("json4s"));
+        Assert.assertEquals(false, additionalProperties.get("circe"));
+    }
+
+    @Test
+    public void shouldUseCirceIfExplicitlyAskTo() {
+        ScalaSttpClientCodegen.JsonLibraryProperty property = new ScalaSttpClientCodegen.JsonLibraryProperty();
+        Map<String, Object> additionalProperties = new HashMap<>();
+        additionalProperties.put("jsonLibrary", "circe");
+        property.updateAdditionalProperties(additionalProperties);
+        Assert.assertEquals(false, additionalProperties.get("json4s"));
+        Assert.assertEquals(true, additionalProperties.get("circe"));
+    }
+}
diff --git a/modules/openapi-generator/src/test/java/org/openapitools/codegen/scala/SttpPackagePropertyTest.java b/modules/openapi-generator/src/test/java/org/openapitools/codegen/scala/SttpPackagePropertyTest.java
new file mode 100644
index 00000000000..7aa45197522
--- /dev/null
+++ b/modules/openapi-generator/src/test/java/org/openapitools/codegen/scala/SttpPackagePropertyTest.java
@@ -0,0 +1,59 @@
+package org.openapitools.codegen.scala;
+
+import org.junit.Assert;
+import org.junit.Test;
+import org.openapitools.codegen.CodegenConstants;
+import org.openapitools.codegen.languages.ScalaSttpClientCodegen;
+
+import java.util.HashMap;
+import java.util.Map;
+
+public class SttpPackagePropertyTest {
+    @Test
+    public void shouldUseDefaultPackageNameIfAdditionalPropertiesAreEmpty(){
+        ScalaSttpClientCodegen.PackageProperty property = new ScalaSttpClientCodegen.PackageProperty();
+        Map<String, Object> additionalProperties = new HashMap<>();
+        property.updateAdditionalProperties(additionalProperties);
+
+        Assert.assertEquals(ScalaSttpClientCodegen.DEFAULT_PACKAGE_NAME + ".api",
+                additionalProperties.get(CodegenConstants.API_PACKAGE));
+        Assert.assertEquals(ScalaSttpClientCodegen.DEFAULT_PACKAGE_NAME + ".model",
+                additionalProperties.get(CodegenConstants.MODEL_PACKAGE));
+        Assert.assertEquals(ScalaSttpClientCodegen.DEFAULT_PACKAGE_NAME + ".core",
+                additionalProperties.get(CodegenConstants.INVOKER_PACKAGE));
+    }
+
+    @Test
+    public void shouldUseCustomMainPackageNameIfProvided(){
+        ScalaSttpClientCodegen.PackageProperty property = new ScalaSttpClientCodegen.PackageProperty();
+        Map<String, Object> additionalProperties = new HashMap<>();
+        String customPackageName = "my.custom.pkg.name";
+        additionalProperties.put("mainPackage", customPackageName);
+        property.updateAdditionalProperties(additionalProperties);
+
+        Assert.assertEquals(customPackageName + ".api",
+                additionalProperties.get(CodegenConstants.API_PACKAGE));
+        Assert.assertEquals(customPackageName + ".model",
+                additionalProperties.get(CodegenConstants.MODEL_PACKAGE));
+        Assert.assertEquals(customPackageName + ".core",
+                additionalProperties.get(CodegenConstants.INVOKER_PACKAGE));
+    }
+
+    @Test
+    public void shouldAllowToMixCustomPackages(){
+        ScalaSttpClientCodegen.PackageProperty property = new ScalaSttpClientCodegen.PackageProperty();
+        Map<String, Object> additionalProperties = new HashMap<>();
+        String customPackageName = "my.custom.pkg.name";
+        additionalProperties.put("mainPackage", customPackageName);
+        String otherCustomPackageName = "some.other.custom.pkg.api";
+        additionalProperties.put(CodegenConstants.API_PACKAGE, otherCustomPackageName);
+        property.updateAdditionalProperties(additionalProperties);
+
+        Assert.assertEquals(otherCustomPackageName,
+                additionalProperties.get(CodegenConstants.API_PACKAGE));
+        Assert.assertEquals(customPackageName + ".model",
+                additionalProperties.get(CodegenConstants.MODEL_PACKAGE));
+        Assert.assertEquals(customPackageName + ".core",
+                additionalProperties.get(CodegenConstants.INVOKER_PACKAGE));
+    }
+}
diff --git a/modules/openapi-generator/src/test/java/org/openapitools/codegen/scala/SttpStringPropertyTest.java b/modules/openapi-generator/src/test/java/org/openapitools/codegen/scala/SttpStringPropertyTest.java
new file mode 100644
index 00000000000..f0db3bdafd3
--- /dev/null
+++ b/modules/openapi-generator/src/test/java/org/openapitools/codegen/scala/SttpStringPropertyTest.java
@@ -0,0 +1,30 @@
+package org.openapitools.codegen.scala;
+
+import org.junit.Assert;
+import org.junit.Test;
+import org.openapitools.codegen.languages.ScalaSttpClientCodegen;
+
+import java.util.HashMap;
+import java.util.Map;
+
+public class SttpStringPropertyTest {
+
+    @Test
+    public void shouldUseDefaultValueIfAdditionalPropertiesAreEmpty(){
+        ScalaSttpClientCodegen.StringProperty property = new ScalaSttpClientCodegen.StringProperty("k1", "desc", "default");
+        Map<String, Object> additionalProperties = new HashMap<>();
+        property.updateAdditionalProperties(additionalProperties);
+
+        Assert.assertEquals("default", additionalProperties.get("k1"));
+    }
+
+    @Test
+    public void shouldUseGivenValueIfProvided(){
+        ScalaSttpClientCodegen.StringProperty property = new ScalaSttpClientCodegen.StringProperty("k1", "desc", "default");
+        Map<String, Object> additionalProperties = new HashMap<>();
+        additionalProperties.put("k1", "custom");
+        property.updateAdditionalProperties(additionalProperties);
+
+        Assert.assertEquals("custom", additionalProperties.get("k1"));
+    }
+}
-- 
GitLab


From 1f9cd3e9657c748e0fa8c78c7aaab25fdcef7ea3 Mon Sep 17 00:00:00 2001
From: Kasper Kondzielski <ghostbuster91@users.noreply.github.com>
Date: Mon, 29 Jun 2020 13:04:05 +0200
Subject: [PATCH 36/38] Update samples/client/petstore/scala-sttp/build.sbt

Co-authored-by: eugeniyk <keatrance@gmail.com>
---
 samples/client/petstore/scala-sttp/build.sbt | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/samples/client/petstore/scala-sttp/build.sbt b/samples/client/petstore/scala-sttp/build.sbt
index e7d77cdd2db..f70d6cebfd7 100644
--- a/samples/client/petstore/scala-sttp/build.sbt
+++ b/samples/client/petstore/scala-sttp/build.sbt
@@ -3,7 +3,7 @@ name := "scala-sttp-petstore"
 organization := "org.openapitools"
 
 scalaVersion := "2.13.2"
-crossScalaVersions := Seq(scalaVersion.value, "2.12.10")
+crossScalaVersions := Seq(scalaVersion.value, "2.12.11")
 
 libraryDependencies ++= Seq(
   "com.softwaremill.sttp.client" %% "core" % "2.2.0",
-- 
GitLab


From a6647d287f304f4b41bed5e19918ee8e5a415909 Mon Sep 17 00:00:00 2001
From: ghostbuster91 <kghost0@gmail.com>
Date: Mon, 29 Jun 2020 13:07:35 +0200
Subject: [PATCH 37/38] Update sbt to 1.3.12

---
 .../main/resources/scala-sttp/project/build.properties.mustache | 2 +-
 samples/client/petstore/scala-sttp/project/build.properties     | 2 +-
 2 files changed, 2 insertions(+), 2 deletions(-)

diff --git a/modules/openapi-generator/src/main/resources/scala-sttp/project/build.properties.mustache b/modules/openapi-generator/src/main/resources/scala-sttp/project/build.properties.mustache
index 6d441921c88..654fe70c42c 100644
--- a/modules/openapi-generator/src/main/resources/scala-sttp/project/build.properties.mustache
+++ b/modules/openapi-generator/src/main/resources/scala-sttp/project/build.properties.mustache
@@ -1 +1 @@
-sbt.version=1.2.4
+sbt.version=1.3.12
diff --git a/samples/client/petstore/scala-sttp/project/build.properties b/samples/client/petstore/scala-sttp/project/build.properties
index 6d441921c88..654fe70c42c 100644
--- a/samples/client/petstore/scala-sttp/project/build.properties
+++ b/samples/client/petstore/scala-sttp/project/build.properties
@@ -1 +1 @@
-sbt.version=1.2.4
+sbt.version=1.3.12
-- 
GitLab


From 8f5a98f036a846ba113dba13e9b8cb839b9a6f81 Mon Sep 17 00:00:00 2001
From: ghostbuster91 <kghost0@gmail.com>
Date: Mon, 29 Jun 2020 15:05:07 +0200
Subject: [PATCH 38/38] Run bin/utils/ensure-up-to-date and commit changes

---
 docs/generators/scala-sttp.md                | 14 +++++++-------
 samples/client/petstore/scala-sttp/build.sbt |  2 +-
 2 files changed, 8 insertions(+), 8 deletions(-)

diff --git a/docs/generators/scala-sttp.md b/docs/generators/scala-sttp.md
index ab09d61bac4..420682ca082 100644
--- a/docs/generators/scala-sttp.md
+++ b/docs/generators/scala-sttp.md
@@ -7,23 +7,23 @@ sidebar_label: scala-sttp
 | ------ | ----------- | ------ | ------- |
 |allowUnicodeIdentifiers|boolean, toggles whether unicode identifiers are allowed in names or not, default is false| |false|
 |apiPackage|package for generated api classes| |null|
-|sttpClientVersion|Option. Allows to override default version of sttp client library. Minimal version required for this project to compile is 2.2.0 |2.2.0
+|circeVersion|The version of circe library| |0.13.0|
 |dateLibrary|Option. Date library to use|<dl><dt>**joda**</dt><dd>Joda (for legacy app)</dd><dt>**java8**</dt><dd>Java 8 native JSR310 (prefered for JDK 1.8+)</dd></dl>|java8|
-|jodaTimeVersion|Only if dateLibrary was set to joda. Allows to override default jodatime version.|2.10.6
-|json4sVersion|Only if jsonLibrary was set to json4s. Allows to override default json4s version.|3.6.8
-|circeVersion|Only if jsonLibrary was set to circe. Allows to override default circe version.|0.13.0 
-|jsonLibrary|Option. Json library to use|<dl><dt>**json4s**</dt>https://github.com/json4s/json4s<dt>**circe**</dt><dd>https://github.com/circe/circe</dd></dl>|json4s|
-|separateErrorChannel| Option. Whether to return response as `F[Either[ResponseError[ErrorType], ReturnType]]]` or to flatten response's error raising them through enclosing monad (`F[ReturnType]`).|true
 |disallowAdditionalPropertiesIfNotPresent|Specify the behavior when the 'additionalProperties' keyword is not present in the OAS document. If false: the 'additionalProperties' implementation is compliant with the OAS and JSON schema specifications. If true: when the 'additionalProperties' keyword is not present in a schema, the value of 'additionalProperties' is set to false, i.e. no additional properties are allowed. Note: this mode is not compliant with the JSON schema specification. This is the original openapi-generator behavior.This setting is currently ignored for OAS 2.0 documents:  1) When the 'additionalProperties' keyword is not present in a 2.0 schema, additional properties are NOT allowed.  2) Boolean values of the 'additionalProperties' keyword are ignored. It's as if additional properties are NOT allowed.Note: the root cause are issues #1369 and #1371, which must be resolved in the swagger-parser project.|<dl><dt>**false**</dt><dd>The 'additionalProperties' implementation is compliant with the OAS and JSON schema specifications.</dd><dt>**true**</dt><dd>when the 'additionalProperties' keyword is not present in a schema, the value of 'additionalProperties' is automatically set to false, i.e. no additional properties are allowed. Note: this mode is not compliant with the JSON schema specification. This is the original openapi-generator behavior.</dd></dl>|true|
 |ensureUniqueParams|Whether to ensure parameter names are unique in an operation (rename parameters that are not).| |true|
+|jodaTimeVersion|The version of joda-time library| |2.10.6|
+|json4sVersion|The version of json4s library| |3.6.8|
+|jsonLibrary|Json library to use. Possible values are: json4s and circe.| |json4s|
 |legacyDiscriminatorBehavior|This flag is used by OpenAPITools codegen to influence the processing of the discriminator attribute in OpenAPI documents. This flag has no impact if the OAS document does not use the discriminator attribute. The default value of this flag is set in each language-specific code generator (e.g. Python, Java, go...)using the method toModelName. Note to developers supporting a language generator in OpenAPITools; to fully support the discriminator attribute as defined in the OAS specification 3.x, language generators should set this flag to true by default; however this requires updating the mustache templates to generate a language-specific discriminator lookup function that iterates over {{#mappedModels}} and does not iterate over {{children}}, {{#anyOf}}, or {{#oneOf}}.|<dl><dt>**true**</dt><dd>The mapping in the discriminator includes descendent schemas that allOf inherit from self and the discriminator mapping schemas in the OAS document.</dd><dt>**false**</dt><dd>The mapping in the discriminator includes any descendent schemas that allOf inherit from self, any oneOf schemas, any anyOf schemas, any x-discriminator-values, and the discriminator mapping schemas in the OAS document AND Codegen validates that oneOf and anyOf schemas contain the required discriminator and throws an error if the discriminator is missing.</dd></dl>|true|
 |mainPackage|Top-level package name, which defines 'apiPackage', 'modelPackage', 'invokerPackage'| |org.openapitools.client|
 |modelPackage|package for generated models| |null|
 |modelPropertyNaming|Naming convention for the property: 'camelCase', 'PascalCase', 'snake_case' and 'original', which keeps the original name| |camelCase|
 |prependFormOrBodyParameters|Add form or body parameters to the beginning of the parameter list.| |false|
+|separateErrorChannel|Whether to return response as F[Either[ResponseError[ErrorType], ReturnType]]] or to flatten response's error raising them through enclosing monad (F[ReturnType]).| |true|
 |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|
+|sttpClientVersion|The version of sttp client| |2.2.0|
 
 ## IMPORT MAPPING
 
@@ -87,7 +87,7 @@ sidebar_label: scala-sttp
 <li>final</li>
 <li>finally</li>
 <li>for</li>
-<li>forsome</li>
+<li>forSome</li>
 <li>if</li>
 <li>implicit</li>
 <li>import</li>
diff --git a/samples/client/petstore/scala-sttp/build.sbt b/samples/client/petstore/scala-sttp/build.sbt
index f70d6cebfd7..e7d77cdd2db 100644
--- a/samples/client/petstore/scala-sttp/build.sbt
+++ b/samples/client/petstore/scala-sttp/build.sbt
@@ -3,7 +3,7 @@ name := "scala-sttp-petstore"
 organization := "org.openapitools"
 
 scalaVersion := "2.13.2"
-crossScalaVersions := Seq(scalaVersion.value, "2.12.11")
+crossScalaVersions := Seq(scalaVersion.value, "2.12.10")
 
 libraryDependencies ++= Seq(
   "com.softwaremill.sttp.client" %% "core" % "2.2.0",
-- 
GitLab