From 91cb31736e534e494f25c46fc1c6bdbb49357dc1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C5=81ukasz=20Sowa?= Date: Fri, 23 Feb 2024 17:42:16 +0100 Subject: [PATCH] Pekko support --- .scalafmt.conf | 21 +- .../baklava/routes/BaklavaRoutes.scala | 19 +- build.sbt | 280 ++++++++---------- .../circe/CirceJsonStringProvider.scala | 8 +- .../model/EnrichedRouteRepresentation.scala | 14 +- .../baklava/core/model/RouteDtoHandler.scala | 40 +-- .../model/RouteHeaderRepresentation.scala | 5 +- .../model/RouteParameterRepresentation.scala | 10 +- .../core/model/RouteRepresentation.scala | 18 +- .../JsonSchemaToSwaggerSchemaWorker.scala | 81 +++-- .../openapi/OpenApiFormatterWorker.scala | 79 ++--- .../openapi/builders/OpenApiBuilder.scala | 6 +- .../openapi/builders/OperationBuilder.scala | 14 +- .../openapi/builders/PathItemBuilder.scala | 12 +- .../OpenApiFormatterWorkerSpec.scala | 93 ++---- .../JsonSchemaToSwaggerSchemaWorkerSpec.scala | 105 +++---- .../formatter/SimpleDocsFormatter.scala | 18 +- .../baklava/formatter/TsFormatter.scala | 80 ++--- .../baklava/generator/Generator.scala | 16 +- .../pl/iterators/baklava/generator/Main.scala | 2 +- .../generator/GeneratorCirceSpec.scala | 15 +- .../generator/GeneratorSpraySpec.scala | 15 +- .../baklava/routes/BaklavaRoutes.scala | 22 +- .../src/main/resources/reference.conf | 20 ++ .../baklava/routes/BaklavaRoutes.scala | 94 ++++++ .../pekkohttp/PekkoHttpRouteBaklavaSpec.scala | 10 + project/plugins.sbt | 5 +- .../baklava/sbtplugin/BaklavaSbtPlugin.scala | 2 +- .../baklava/fetcher/ScalatestFetcher.scala | 2 +- .../AkkaHttpScalatestFetcherSpec.scala | 25 +- .../baklava/fetcher/Specs2Fetcher.scala | 2 +- .../fetcher/AkkaHttpSpecs2FetcherSpec.scala | 19 +- .../sprayjson/SprayJsonStringProvider.scala | 6 +- 33 files changed, 572 insertions(+), 586 deletions(-) create mode 100644 pekko-http-routes/src/main/resources/reference.conf create mode 100644 pekko-http-routes/src/main/scala/pl/iterators/baklava/routes/BaklavaRoutes.scala create mode 100644 pekko-http/src/main/scala/pl/iterators/baklava/pekkohttp/PekkoHttpRouteBaklavaSpec.scala diff --git a/.scalafmt.conf b/.scalafmt.conf index 05812d1..e034a85 100644 --- a/.scalafmt.conf +++ b/.scalafmt.conf @@ -1,4 +1,17 @@ -style = defaultWithAlign -maxColumn = 139 -assumeStandardLibraryStripMargin = true -includeCurlyBraceInSelectChains = true \ No newline at end of file +version = 3.7.17 + +runner.dialect = scala213 +align.arrowEnumeratorGenerator = true +align.openParenCallSite = false +align.tokens = [ "=>", "=", "<-", "extends", "%", "%%", "->" ] +newlines.alwaysBeforeElseAfterCurlyIf = false +maxColumn = 150 +rewrite.rules = [PreferCurlyFors, RedundantBraces, RedundantParens] +spaces { + inImportCurlyBraces = false +} +verticalMultiline.atDefnSite = true +verticalMultiline.arityThreshold = 3 +verticalMultiline.newlineAfterOpenParen = true + +style = IntelliJ \ No newline at end of file diff --git a/akka-http-routes/src/main/scala/pl/iterators/baklava/routes/BaklavaRoutes.scala b/akka-http-routes/src/main/scala/pl/iterators/baklava/routes/BaklavaRoutes.scala index 0dcb5e6..b7a9a74 100644 --- a/akka-http-routes/src/main/scala/pl/iterators/baklava/routes/BaklavaRoutes.scala +++ b/akka-http-routes/src/main/scala/pl/iterators/baklava/routes/BaklavaRoutes.scala @@ -26,7 +26,8 @@ object BaklavaRoutes { } ~ pathPrefix("swagger") { get(complete(swaggerRedirectHttpResponse)) } - } else + } + else RouteDirectives.reject } @@ -57,7 +58,7 @@ object BaklavaRoutes { HttpResponse(status = StatusCodes.SeeOther, headers = Location(s"$swaggerUiUrl?url=$swaggerDocsUrl&layout=BaseLayout") :: Nil) } - private lazy val swaggerWebJar: Route = { + private lazy val swaggerWebJar: Route = extractUnmatchedPath { path => Try((new WebJarAssetLocator).getFullPath("swagger-ui", path.toString)) match { case Success(fullPath) => @@ -68,14 +69,14 @@ object BaklavaRoutes { failWith(e) } } - } - private case class Config(enabled: Boolean, - basicAuthUser: Option[String], - basicAuthPassword: Option[String], - fileSystemPath: String, - publicPathPrefix: String, - apiPublicPathPrefix: String) + private case class Config( + enabled: Boolean, + basicAuthUser: Option[String], + basicAuthPassword: Option[String], + fileSystemPath: String, + publicPathPrefix: String, + apiPublicPathPrefix: String) private object Config { def apply(config: com.typesafe.config.Config): Config = { diff --git a/build.sbt b/build.sbt index 09ccee6..7ef9def 100644 --- a/build.sbt +++ b/build.sbt @@ -1,6 +1,6 @@ import com.jsuereth.sbtpgp.PgpKeys -val scala_2_13 = "2.13.10" +val scala_2_13 = "2.13.13" val mainScalaVersion = scala_2_13 val supportedScalaVersions = Seq(scala_2_13) @@ -14,7 +14,6 @@ lazy val baseSettings = Seq( organizationName := "Iterators", homepage := Some(url("https://github.com/theiterators/baklava")), scalacOptions := Seq("-deprecation", "-unchecked", "-feature", "-encoding", "utf8"), - scalafmtVersion := "1.3.0", crossScalaVersions := supportedScalaVersions, scalafmtOnCompile := true, // Sonatype settings sonatypeProfileName := "pl.iterators", @@ -23,18 +22,10 @@ lazy val baseSettings = Seq( organizationName := "Iterators", organizationHomepage := Some(url("https://www.iteratorshq.com/")), developers := List( - Developer( - id = "kpalcowski", - name = "Krzysztof Palcowski", - email = "kpalcowski@iteratorshq.com", - url = url("https://github.com/kristerr") - ) + Developer(id = "kpalcowski", name = "Krzysztof Palcowski", email = "kpalcowski@iteratorshq.com", url = url("https://github.com/kristerr")) ), scmInfo := Some( - ScmInfo( - browseUrl = url("https://github.com/theiterators/baklava"), - connection = "scm:git:https://github.com/theiterators/baklava.git" - ) + ScmInfo(browseUrl = url("https://github.com/theiterators/baklava"), connection = "scm:git:https://github.com/theiterators/baklava.git") ), // credentials += Credentials(Path.userHome / ".ivy2" / ".credentials"), crossScalaVersions := supportedScalaVersions @@ -42,106 +33,92 @@ lazy val baseSettings = Seq( val akkaV = "2.6.20" val akkaHttpV = "10.2.10" +val pekkoV = "1.0.2" +val pekkoHttpV = "1.0.1" val http4sStirV = "0.2" -val typesafeConfigV = "1.4.2" +val typesafeConfigV = "1.4.3" val kebsV = "1.9.7" val reflectionsV = "0.10.2" -val specs2V = "4.16.1" +val specs2V = "4.20.5" val jsonSchemaV = "0.7.11" -val swaggerV = "2.1.6" -val scalatestV = "3.2.12" -val webjarsLocatorV = "0.45" +val swaggerV = "2.2.20" +val scalatestV = "3.2.18" +val webjarsLocatorV = "0.50" val swaggerUiV = "3.40.0" //unfortunately we need to stuck with this version lazy val akkahttproutes = project .in(file("akka-http-routes")) .settings(baseSettings: _*) - .settings( - name := "akka-http-routes", - moduleName := "baklava-akka-http-routes" - ) - .settings( - libraryDependencies ++= { - Seq( - "com.typesafe.akka" %% "akka-http" % akkaHttpV, - "com.typesafe" % "config" % typesafeConfigV, - "org.webjars" % "webjars-locator" % webjarsLocatorV, - "org.webjars" % "swagger-ui" % swaggerUiV - ) - } - ) + .settings(name := "akka-http-routes", moduleName := "baklava-akka-http-routes") + .settings(libraryDependencies ++= { + Seq( + "com.typesafe.akka" %% "akka-http" % akkaHttpV, + "com.typesafe" % "config" % typesafeConfigV, + "org.webjars" % "webjars-locator" % webjarsLocatorV, + "org.webjars" % "swagger-ui" % swaggerUiV + ) + }) + +lazy val pekkohttproutes = project + .in(file("pekko-http-routes")) + .settings(baseSettings: _*) + .settings(name := "pekko-http-routes", moduleName := "baklava-pekko-http-routes") + .settings(libraryDependencies ++= { + Seq( + "org.apache.pekko" %% "pekko-http" % pekkoHttpV, + "com.typesafe" % "config" % typesafeConfigV, + "org.webjars" % "webjars-locator" % webjarsLocatorV, + "org.webjars" % "swagger-ui" % swaggerUiV + ) + }) lazy val http4sstirroutes = project .in(file("http4s-stir-routes")) .settings(baseSettings: _*) - .settings( - name := "http4s-stir-routes", - moduleName := "baklava-http4s-stir-routes" - ) - .settings( - libraryDependencies ++= { + .settings(name := "http4s-stir-routes", moduleName := "baklava-http4s-stir-routes") + .settings(libraryDependencies ++= { - Seq( - "pl.iterators" %% "http4s-stir" % http4sStirV, - "com.typesafe" % "config" % typesafeConfigV, - "org.webjars" % "webjars-locator" % webjarsLocatorV, - "org.webjars" % "swagger-ui" % swaggerUiV - ) - } - ) + Seq( + "pl.iterators" %% "http4s-stir" % http4sStirV, + "com.typesafe" % "config" % typesafeConfigV, + "org.webjars" % "webjars-locator" % webjarsLocatorV, + "org.webjars" % "swagger-ui" % swaggerUiV + ) + }) lazy val core = project .in(file("core")) .settings(baseSettings: _*) - .settings( - name := "core", - moduleName := "baklava-core" - ) - .settings( - libraryDependencies ++= { - Seq( - "pl.iterators" %% "kebs-tagged-meta" % kebsV, - "pl.iterators" %% "kebs-jsonschema" % kebsV, - "pl.iterators" %% "kebs-scalacheck" % kebsV, - "com.github.andyglow" %% "scala-jsonschema" % jsonSchemaV, - "com.github.andyglow" %% "scala-jsonschema-enumeratum" % jsonSchemaV, - "org.reflections" % "reflections" % reflectionsV, - "org.specs2" %% "specs2-core" % specs2V % "test" - ) - } - ) + .settings(name := "core", moduleName := "baklava-core") + .settings(libraryDependencies ++= { + Seq( + "pl.iterators" %% "kebs-tagged-meta" % kebsV, + "pl.iterators" %% "kebs-jsonschema" % kebsV, + "pl.iterators" %% "kebs-scalacheck" % kebsV, + "com.github.andyglow" %% "scala-jsonschema" % jsonSchemaV, + "com.github.andyglow" %% "scala-jsonschema-enumeratum" % jsonSchemaV, + "org.reflections" % "reflections" % reflectionsV, + "org.specs2" %% "specs2-core" % specs2V % "test" + ) + }) lazy val circe = project .in(file("circe")) .dependsOn(core % "compile->compile;test->test") .settings(baseSettings: _*) - .settings( - name := "circe", - moduleName := "baklava-circe" - ) - .settings( - libraryDependencies ++= { - Seq( - "pl.iterators" %% "kebs-circe" % kebsV - ) - } - ) + .settings(name := "circe", moduleName := "baklava-circe") + .settings(libraryDependencies ++= { + Seq("pl.iterators" %% "kebs-circe" % kebsV) + }) lazy val sprayjson = project .in(file("sprayjson")) .dependsOn(core % "compile->compile;test->test") .settings(baseSettings: _*) - .settings( - name := "sprayjson", - moduleName := "baklava-sprayjson" - ) - .settings( - libraryDependencies ++= { - Seq( - "pl.iterators" %% "kebs-spray-json" % kebsV - ) - } - ) + .settings(name := "sprayjson", moduleName := "baklava-sprayjson") + .settings(libraryDependencies ++= { + Seq("pl.iterators" %% "kebs-spray-json" % kebsV) + }) lazy val formatter = project .in(file("formatter")) @@ -149,81 +126,69 @@ lazy val formatter = project .dependsOn(circe % "test->test") .dependsOn(sprayjson % "test->test") .settings(baseSettings: _*) - .settings( - name := "formatter", - moduleName := "baklava-formatter" - ) + .settings(name := "formatter", moduleName := "baklava-formatter") lazy val formatteropenapi = project .in(file("formatter-openapi")) .dependsOn(core % "compile->compile;test->test") .dependsOn(formatter % "compile->compile;test->test") .settings(baseSettings: _*) - .settings( - name := "formatter-openapi", - moduleName := "baklava-formatter-openapi" - ) - .settings( - libraryDependencies ++= { - Seq( - "io.swagger.core.v3" % "swagger-core" % swaggerV - ) - } - ) + .settings(name := "formatter-openapi", moduleName := "baklava-formatter-openapi") + .settings(libraryDependencies ++= { + Seq("io.swagger.core.v3" % "swagger-core" % swaggerV) + }) lazy val generator = project .in(file("generator")) .dependsOn(core % "compile->compile;test->test") .dependsOn(formatter % "compile->compile;test->test") .settings(baseSettings: _*) - .settings( - name := "generator", - moduleName := "baklava-generator" - ) - .settings( - libraryDependencies ++= { - Seq( - "org.reflections" % "reflections" % reflectionsV - ) - } - ) + .settings(name := "generator", moduleName := "baklava-generator") + .settings(libraryDependencies ++= { + Seq("org.reflections" % "reflections" % reflectionsV) + }) lazy val akkahttp = project .in(file("akka-http")) .dependsOn(core % "compile->compile;test->test") .settings(baseSettings: _*) - .settings( - name := "akka-http", - moduleName := "baklava-akka-http" - ) - .settings( - libraryDependencies ++= { + .settings(name := "akka-http", moduleName := "baklava-akka-http") + .settings(libraryDependencies ++= { - Seq( - "pl.iterators" %% "kebs-akka-http" % kebsV, - "com.typesafe.akka" %% "akka-slf4j" % akkaV, - "com.typesafe.akka" %% "akka-stream" % akkaV, - "com.typesafe.akka" %% "akka-http-core" % akkaHttpV, - "com.typesafe.akka" %% "akka-http-testkit" % akkaHttpV % "test" - ) - } - ) + Seq( + "pl.iterators" %% "kebs-akka-http" % kebsV, + "com.typesafe.akka" %% "akka-slf4j" % akkaV, + "com.typesafe.akka" %% "akka-stream" % akkaV, + "com.typesafe.akka" %% "akka-http-core" % akkaHttpV, + "com.typesafe.akka" %% "akka-http-testkit" % akkaHttpV % "test" + ) + }) + +lazy val pekkohttp = project + .in(file("pekko-http")) + .dependsOn(core % "compile->compile;test->test") + .settings(baseSettings: _*) + .settings(name := "pekko-http", moduleName := "baklava-pekko-http") + .settings(libraryDependencies ++= { + + Seq( + "pl.iterators" %% "kebs-pekko-http" % kebsV, + "org.apache.pekko" %% "pekko-slf4j" % pekkoV, + "org.apache.pekko" %% "pekko-stream" % pekkoV, + "org.apache.pekko" %% "pekko-http-core" % pekkoHttpV, + "org.apache.pekko" %% "pekko-http-testkit" % pekkoHttpV % "test" + ) + }) lazy val http4sstir = project .in(file("http4s-stir")) .dependsOn(core % "compile->compile;test->test") .settings(baseSettings: _*) - .settings( - name := "http4s-stir", - moduleName := "baklava-http4s-stir" - ) + .settings(name := "http4s-stir", moduleName := "baklava-http4s-stir") .settings( libraryDependencies ++= { - Seq( - "pl.iterators" %% "http4s-stir" % http4sStirV, - "pl.iterators" %% "http4s-stir-testkit" % http4sStirV - ) + Seq("pl.iterators" %% "http4s-stir" % http4sStirV, "pl.iterators" %% "http4s-stir-testkit" % http4sStirV) }, crossScalaVersions := Seq(scala_2_13) ) @@ -234,41 +199,29 @@ lazy val scalatest = project .dependsOn(akkahttp % "test->test") .dependsOn(circe % "test->test") .settings(baseSettings: _*) - .settings( - name := "scalatest", - moduleName := "baklava-scalatest" - ) - .settings( - libraryDependencies ++= { + .settings(name := "scalatest", moduleName := "baklava-scalatest") + .settings(libraryDependencies ++= { - Seq( - "org.scalatest" %% "scalatest" % scalatestV - ) - } - ) + Seq("org.scalatest" %% "scalatest" % scalatestV) + }) lazy val specs2 = project .in(file("specs2")) .dependsOn(core % "compile->compile;test->test") .dependsOn(sprayjson % "test->test") .settings(baseSettings: _*) - .settings( - name := "specs2", - moduleName := "baklava-specs2" - ) - .settings( - libraryDependencies ++= { + .settings(name := "specs2", moduleName := "baklava-specs2") + .settings(libraryDependencies ++= { - Seq( - "org.specs2" %% "specs2-core" % specs2V, - "com.typesafe.akka" %% "akka-stream" % akkaV % "test", - "com.typesafe.akka" %% "akka-stream-testkit" % akkaV % "test", - "com.typesafe.akka" %% "akka-testkit" % akkaV % "test", - "com.typesafe.akka" %% "akka-http-core" % akkaHttpV % "test", - "com.typesafe.akka" %% "akka-http-testkit" % akkaHttpV % "test" - ) - } - ) + Seq( + "org.specs2" %% "specs2-core" % specs2V, + "com.typesafe.akka" %% "akka-stream" % akkaV % "test", + "com.typesafe.akka" %% "akka-stream-testkit" % akkaV % "test", + "com.typesafe.akka" %% "akka-testkit" % akkaV % "test", + "com.typesafe.akka" %% "akka-http-core" % akkaHttpV % "test", + "com.typesafe.akka" %% "akka-http-testkit" % akkaHttpV % "test" + ) + }) lazy val sbtplugin = project .in(file("sbtplugin")) @@ -299,12 +252,11 @@ lazy val baklava = project akkahttproutes, http4sstir, http4sstirroutes, + pekkohttp, + pekkohttproutes, scalatest, specs2, sbtplugin ) .settings(baseSettings: _*) - .settings( - name := "baklava", - description := "Library to generate docs" - ) + .settings(name := "baklava", description := "Library to generate docs") diff --git a/circe/src/main/scala/pl/iterators/baklava/circe/CirceJsonStringProvider.scala b/circe/src/main/scala/pl/iterators/baklava/circe/CirceJsonStringProvider.scala index 14100eb..511d878 100644 --- a/circe/src/main/scala/pl/iterators/baklava/circe/CirceJsonStringProvider.scala +++ b/circe/src/main/scala/pl/iterators/baklava/circe/CirceJsonStringProvider.scala @@ -5,12 +5,8 @@ import pl.iterators.baklava.core.model.JsonStringPrinter trait CirceJsonStringProvider { - implicit val unitPrinter = new JsonStringPrinter[Unit] { - override def printJson(obj: Unit): String = "" - } + implicit val unitPrinter: JsonStringPrinter[Unit] = (obj: Unit) => "" - implicit def circeJsonString[T](implicit encoder: Encoder[T]) = new JsonStringPrinter[T] { - override def printJson(obj: T): String = encoder.apply(obj).toString() - } + implicit def circeJsonString[T](implicit encoder: Encoder[T]): JsonStringPrinter[T] = (obj: T) => encoder.apply(obj).toString() } diff --git a/core/src/main/scala/pl/iterators/baklava/core/model/EnrichedRouteRepresentation.scala b/core/src/main/scala/pl/iterators/baklava/core/model/EnrichedRouteRepresentation.scala index 7ffb7ec..e192551 100644 --- a/core/src/main/scala/pl/iterators/baklava/core/model/EnrichedRouteRepresentation.scala +++ b/core/src/main/scala/pl/iterators/baklava/core/model/EnrichedRouteRepresentation.scala @@ -1,9 +1,8 @@ package pl.iterators.baklava.core.model class EnrichedRouteRepresentation[Request, Response] private ( - val routeRepresentation: RouteRepresentation[Request, Response], - val enrichDescriptions: Seq[EnrichedDescription] -) { + val routeRepresentation: RouteRepresentation[Request, Response], + val enrichDescriptions: Seq[EnrichedDescription]) { override def equals(o: Any): Boolean = o match { case p: EnrichedRouteRepresentation[_, _] => p.routeRepresentation.equals(routeRepresentation) && p.enrichDescriptions.equals(enrichDescriptions) @@ -12,20 +11,17 @@ class EnrichedRouteRepresentation[Request, Response] private ( } class EnrichedDescription private (val description: String, val statusCodeOpt: Option[Int]) { - override def equals(o: Any): Boolean = { + override def equals(o: Any): Boolean = o match { case p: EnrichedDescription => p.description.equals(description) && p.statusCodeOpt.equals(statusCodeOpt) case _ => false } - } } object EnrichedRouteRepresentation { - def apply[Request, Response]( - routeRepresentation: RouteRepresentation[Request, Response], - descriptions: Seq[String] - ): EnrichedRouteRepresentation[Request, Response] = + def apply[Request, Response](routeRepresentation: RouteRepresentation[Request, Response], descriptions: Seq[String]) + : EnrichedRouteRepresentation[Request, Response] = new EnrichedRouteRepresentation(routeRepresentation, descriptions.map(EnrichedDescription.apply)) } diff --git a/core/src/main/scala/pl/iterators/baklava/core/model/RouteDtoHandler.scala b/core/src/main/scala/pl/iterators/baklava/core/model/RouteDtoHandler.scala index d283561..1386c1e 100644 --- a/core/src/main/scala/pl/iterators/baklava/core/model/RouteDtoHandler.scala +++ b/core/src/main/scala/pl/iterators/baklava/core/model/RouteDtoHandler.scala @@ -7,10 +7,11 @@ import pl.iterators.baklava.core.utils.option.RichOptionCompanion import scala.reflect.runtime.universe._ import scala.util.Random -class RouteDtoHandler[T](implicit ttag: TypeTag[T], - generators: AllGenerators[T], - val jsonSchemaWrapper: JsonSchemaWrapper[T], - jsonPrinter: JsonStringPrinter[T]) { +class RouteDtoHandler[T]( + implicit ttag: TypeTag[T], + generators: AllGenerators[T], + val jsonSchemaWrapper: JsonSchemaWrapper[T], + jsonPrinter: JsonStringPrinter[T]) { lazy val isUnit = ttag == implicitly[TypeTag[Unit]] @@ -34,10 +35,13 @@ class RouteDtoHandler[T](implicit ttag: TypeTag[T], } } -class RouteDtoHandlerWithPredefinedValue[T](value: T)(implicit ttag: TypeTag[T], - generators: AllGenerators[T], - override val jsonSchemaWrapper: JsonSchemaWrapper[T], - jsonPrinter: JsonStringPrinter[T]) +class RouteDtoHandlerWithPredefinedValue[T]( + value: T +)(implicit + ttag: TypeTag[T], + generators: AllGenerators[T], + override val jsonSchemaWrapper: JsonSchemaWrapper[T], + jsonPrinter: JsonStringPrinter[T]) extends RouteDtoHandler { override lazy val normal: RouteDtoValueWithJsonOpt[T] = @@ -45,11 +49,13 @@ class RouteDtoHandlerWithPredefinedValue[T](value: T)(implicit ttag: TypeTag[T], } object RouteDtoHandler { - def apply[T](predefinedValue: Option[T])( - implicit ttag: TypeTag[T], - generators: AllGenerators[T], - jsonSchemaWrapper: JsonSchemaWrapper[T], - jsonPrinter: JsonStringPrinter[T] + def apply[T]( + predefinedValue: Option[T] + )(implicit + ttag: TypeTag[T], + generators: AllGenerators[T], + jsonSchemaWrapper: JsonSchemaWrapper[T], + jsonPrinter: JsonStringPrinter[T] ): RouteDtoHandler[T] = predefinedValue.fold(new RouteDtoHandler[T])(value => new RouteDtoHandlerWithPredefinedValue[T](value)) } @@ -60,12 +66,8 @@ class RouteDtoValueWithJsonOpt[T] private (val value: T, val jsonString: Option[ object RouteDtoValueWithJsonOpt { - def apply[T](value: T)(implicit ttag: TypeTag[T], jsonPrinter: JsonStringPrinter[T]): RouteDtoValueWithJsonOpt[T] = { - new RouteDtoValueWithJsonOpt[T]( - value, - Option.when(ttag != implicitly[TypeTag[Unit]])(jsonPrinter.printJson(value)) - ) - } + def apply[T](value: T)(implicit ttag: TypeTag[T], jsonPrinter: JsonStringPrinter[T]): RouteDtoValueWithJsonOpt[T] = + new RouteDtoValueWithJsonOpt[T](value, Option.when(ttag != implicitly[TypeTag[Unit]])(jsonPrinter.printJson(value))) } diff --git a/core/src/main/scala/pl/iterators/baklava/core/model/RouteHeaderRepresentation.scala b/core/src/main/scala/pl/iterators/baklava/core/model/RouteHeaderRepresentation.scala index 04ad6b5..11068af 100644 --- a/core/src/main/scala/pl/iterators/baklava/core/model/RouteHeaderRepresentation.scala +++ b/core/src/main/scala/pl/iterators/baklava/core/model/RouteHeaderRepresentation.scala @@ -1,6 +1,3 @@ package pl.iterators.baklava.core.model -case class RouteHeaderRepresentation( - name: String, - required: Boolean -) +case class RouteHeaderRepresentation(name: String, required: Boolean) diff --git a/core/src/main/scala/pl/iterators/baklava/core/model/RouteParameterRepresentation.scala b/core/src/main/scala/pl/iterators/baklava/core/model/RouteParameterRepresentation.scala index 76842c9..f4be7cb 100644 --- a/core/src/main/scala/pl/iterators/baklava/core/model/RouteParameterRepresentation.scala +++ b/core/src/main/scala/pl/iterators/baklava/core/model/RouteParameterRepresentation.scala @@ -3,11 +3,11 @@ package pl.iterators.baklava.core.model import scala.reflect.runtime.universe.TypeTag case class RouteParameterRepresentation[T]( - name: String, - required: Boolean, - sampleValue: T, - marshaller: T => String, - enumValues: Option[Seq[T]] = None + name: String, + required: Boolean, + sampleValue: T, + marshaller: T => String, + enumValues: Option[Seq[T]] = None )(implicit typeTag: TypeTag[T]) { lazy val marshall: String = marshaller(sampleValue) diff --git a/core/src/main/scala/pl/iterators/baklava/core/model/RouteRepresentation.scala b/core/src/main/scala/pl/iterators/baklava/core/model/RouteRepresentation.scala index 6b76e42..990052c 100644 --- a/core/src/main/scala/pl/iterators/baklava/core/model/RouteRepresentation.scala +++ b/core/src/main/scala/pl/iterators/baklava/core/model/RouteRepresentation.scala @@ -7,15 +7,15 @@ import pl.iterators.baklava.core.utils.option.RichOptionCompanion import scala.reflect.runtime.universe._ case class RouteRepresentation[Request, Response]( - description: String, - method: String, - path: String, - parameters: List[RouteParameterRepresentation[_]] = Nil, - headers: List[RouteHeaderRepresentation] = Nil, - requestPredefinedValue: Option[Request] = None, - responsePredefinedValue: Option[Response] = None, - authentication: List[RouteSecurityGroup] = List.empty, - extendedDescription: Option[String] = None + description: String, + method: String, + path: String, + parameters: List[RouteParameterRepresentation[_]] = Nil, + headers: List[RouteHeaderRepresentation] = Nil, + requestPredefinedValue: Option[Request] = None, + responsePredefinedValue: Option[Response] = None, + authentication: List[RouteSecurityGroup] = List.empty, + extendedDescription: Option[String] = None )(implicit requestTypeTag: TypeTag[Request], requestGenerators: AllGenerators[Request], diff --git a/formatter-openapi/src/main/scala/pl/iterators/baklava/formatter/openapi/JsonSchemaToSwaggerSchemaWorker.scala b/formatter-openapi/src/main/scala/pl/iterators/baklava/formatter/openapi/JsonSchemaToSwaggerSchemaWorker.scala index 3212ac0..6eb3266 100644 --- a/formatter-openapi/src/main/scala/pl/iterators/baklava/formatter/openapi/JsonSchemaToSwaggerSchemaWorker.scala +++ b/formatter-openapi/src/main/scala/pl/iterators/baklava/formatter/openapi/JsonSchemaToSwaggerSchemaWorker.scala @@ -2,57 +2,56 @@ package pl.iterators.baklava.formatter.openapi import io.swagger.v3.oas.models.media._ -import scala.collection.JavaConverters._ +import scala.jdk.CollectionConverters._ class JsonSchemaToSwaggerSchemaWorker { - def convert(jsonSchema: json.Schema[_]): Schema[_] = { + def convertMatch(jsonSchema: json.Schema[_]): Schema[_] = jsonSchema match { - case schema: json.Schema.allof[Any] => convert(schema) - case schema: json.Schema.array[Any, Any] => convert(schema) - case schema: json.Schema.boolean => convert(schema) - case schema: json.Schema.`def`[Any] => convert(schema) - case schema: json.Schema.dictionary[Any, Any, Any] => convert(schema) - case schema: json.Schema.`enum`[Any] => convert(schema) - case schema: json.Schema.integer => convert(schema) - case schema: json.Schema.not[Any] => convert(schema) - case schema: json.Schema.number[Any] => convert(schema) - case schema: json.Schema.`object`[Any] => convert(schema) - case schema: json.Schema.oneof[Any] => convert(schema) - case schema: json.Schema.string[Any] => convert(schema) - case schema: json.Schema.ref[Any] => convert(schema) - case schema: json.Schema.`value-class`[Any, Any] => convert(schema) + case schema: json.Schema.allof[_] => convert(schema) + case schema: json.Schema.array[_, _] => convert(schema) + case schema: json.Schema.boolean => convert(schema) + case schema: json.Schema.`def`[_] => convert(schema) + case schema: json.Schema.dictionary[_, _, _] => convert(schema) + case schema: json.Schema.`enum`[_] => convert(schema) + case schema: json.Schema.integer => convert(schema) + case schema: json.Schema.not[_] => convert(schema) + case schema: json.Schema.number[_] => convert(schema) + case schema: json.Schema.`object`[_] => convert(schema) + case schema: json.Schema.oneof[_] => convert(schema) + case schema: json.Schema.string[_] => convert(schema) + case schema: json.Schema.ref[_] => convert(schema) + case schema: json.Schema.`value-class`[_, _] => convert(schema) + case schema: json.Schema.const[_] => convert(schema) } - } - private def convert(schema: json.Schema.allof[Any]): Schema[_] = { + private def convert(schema: json.Schema.allof[_]): Schema[_] = schema.subTypes.headOption .map { childSchema => - convert(childSchema) + convertMatch(childSchema) } .getOrElse(new Schema[Unit]()) - } - private def convert(schema: json.Schema.array[Any, Any]): Schema[_] = { + private def convert[T, C[_]](schema: json.Schema.array[T, C]): Schema[_] = { val output = new ArraySchema - output.setItems(convert(schema.componentType)) + output.setItems(convertMatch(schema.componentType)) output } private def convert(schema: json.Schema.boolean): Schema[_] = new BooleanSchema - private def convert(schema: json.Schema.`def`[Any]): Schema[_] = - convert(schema.tpe) + private def convert(schema: json.Schema.`def`[_]): Schema[_] = + convertMatch(schema.tpe) - private def convert(schema: json.Schema.dictionary[Any, Any, Any]): Schema[_] = { + private def convert[K, V, C[_, _]](schema: json.Schema.dictionary[K, V, C]): Schema[_] = { val output = new ObjectSchema - output.addProperties("^.*$", convert(schema.valueType)) + output.addProperty("^.*$", convertMatch(schema.valueType)) output } - private def convert(schema: json.Schema.`enum`[Any]): Schema[_] = { - convert(schema.tpe) match { + private def convert(schema: json.Schema.`enum`[_]): Schema[_] = + convertMatch(schema.tpe) match { case inner: IntegerSchema => val output = new IntegerSchema output.setEnum(schema.values.map(s => Integer.valueOf(s.toString).asInstanceOf[Number]).toList.asJava) @@ -69,34 +68,31 @@ class JsonSchemaToSwaggerSchemaWorker { output } - } - private def convert(schema: json.Schema.integer): Schema[_] = new IntegerSchema - private def convert(schema: json.Schema.not[Any]): Schema[_] = + private def convert(schema: json.Schema.not[_]): Schema[_] = new Schema[Unit]() - private def convert(schema: json.Schema.number[Any]): Schema[_] = + private def convert(schema: json.Schema.number[_]): Schema[_] = new NumberSchema - private def convert(schema: json.Schema.`object`[Any]): Schema[_] = { + private def convert(schema: json.Schema.`object`[_]): Schema[_] = { val output = new ObjectSchema schema.fields.foreach { f => - output.addProperties(f.name, convert(f.tpe)) + output.addProperty(f.name, convertMatch(f.tpe)) } output.setRequired(schema.fields.filter(_.required).map(_.name).toList.asJava) output } - private def convert(schema: json.Schema.oneof[Any]): Schema[_] = { + private def convert(schema: json.Schema.oneof[_]): Schema[_] = schema.subTypes.headOption .map { childSchema => - convert(childSchema) + convertMatch(childSchema) } .getOrElse(new Schema[Unit]()) - } - private def convert(schema: json.Schema.string[Any]): Schema[_] = { + private def convert(schema: json.Schema.string[_]): Schema[_] = { val output = new StringSchema schema.format.foreach { format => output.setFormat(format.toString) @@ -104,10 +100,13 @@ class JsonSchemaToSwaggerSchemaWorker { output } - private def convert(schema: json.Schema.ref[Any]): Schema[_] = + private def convert(schema: json.Schema.ref[_]): Schema[_] = new Schema[Unit]() - private def convert(schema: json.Schema.`value-class`[Any, Any]): Schema[_] = - convert(schema.tpe) + private def convert(schema: json.Schema.`value-class`[_, _]): Schema[_] = + convertMatch(schema.tpe) + + private def convert(schema: json.Schema.const[_]): Schema[_] = + new StringSchema } diff --git a/formatter-openapi/src/main/scala/pl/iterators/baklava/formatter/openapi/OpenApiFormatterWorker.scala b/formatter-openapi/src/main/scala/pl/iterators/baklava/formatter/openapi/OpenApiFormatterWorker.scala index 473b1a5..d3b689c 100644 --- a/formatter-openapi/src/main/scala/pl/iterators/baklava/formatter/openapi/OpenApiFormatterWorker.scala +++ b/formatter-openapi/src/main/scala/pl/iterators/baklava/formatter/openapi/OpenApiFormatterWorker.scala @@ -14,68 +14,55 @@ import scala.jdk.CollectionConverters._ class OpenApiFormatterWorker(jsonSchemaToSwaggerSchemaWorker: JsonSchemaToSwaggerSchemaWorker) { - def generateOpenApi(routesList: List[EnrichedRouteRepresentation[_, _]]): OpenAPI = { + def generateOpenApi(routesList: List[EnrichedRouteRepresentation[_, _]]): OpenAPI = OpenApiBuilder.build( info = new Info().title("Autogenerated API doc").version("1"), components = routeListToComponents(routesList), paths = routeListToPaths(routesList) ) - } private def routeListToComponents(routesList: List[EnrichedRouteRepresentation[_, _]]): Components = { val components = new Components() - routesList.flatMap(routeToSchemaWithName).foreach { - case (name, schema) => - components.addSchemas(name, schema) + routesList.flatMap(routeToSchemaWithName).foreach { case (name, schema) => + components.addSchemas(name, schema) } - routesList.flatMap(routeSecurityGroupToSecuritySchemaWithName).foreach { - case (name, schema) => - components.addSecuritySchemes(name, schema) + routesList.flatMap(routeSecurityGroupToSecuritySchemaWithName).foreach { case (name, schema) => + components.addSecuritySchemes(name, schema) } components } - private def routeToSchemaWithName(route: EnrichedRouteRepresentation[_, _]): List[(String, Schema[_])] = { - List( - route.routeRepresentation.request, - route.routeRepresentation.response - ).flatMap { dto => + private def routeToSchemaWithName(route: EnrichedRouteRepresentation[_, _]): List[(String, Schema[_])] = + List(route.routeRepresentation.request, route.routeRepresentation.response).flatMap { dto => dto.scalaClassOpt.map { scalaClassName => - ( - schemaClassName(scalaClassName), - swaggerSchema(dto.jsonSchemaWrapper) - ) + (schemaClassName(scalaClassName), swaggerSchema(dto.jsonSchemaWrapper)) } } - } private def routeListToPaths(routesList: List[EnrichedRouteRepresentation[_, _]]): Paths = { val paths = new Paths() - routesList.groupBy(_.routeRepresentation.path).toList.sortBy(_._1).foreach { - case (path, routes) => - paths.addPathItem(path, routeGroupedByPathToPathItem(path, routes)) + routesList.groupBy(_.routeRepresentation.path).toList.sortBy(_._1).foreach { case (path, routes) => + paths.addPathItem(path, routeGroupedByPathToPathItem(path, routes)) } paths } - private def routeGroupedByPathToPathItem(path: String, routes: List[EnrichedRouteRepresentation[_, _]]): PathItem = { + private def routeGroupedByPathToPathItem(path: String, routes: List[EnrichedRouteRepresentation[_, _]]): PathItem = PathItemBuilder.build( parameters = extractParamsFromPath(path), get = extractOperationFromGroupedByPath(routes, "GET"), post = extractOperationFromGroupedByPath(routes, "POST"), patch = extractOperationFromGroupedByPath(routes, "PATCH"), put = extractOperationFromGroupedByPath(routes, "PUT"), - delete = extractOperationFromGroupedByPath(routes, "DELETE"), + delete = extractOperationFromGroupedByPath(routes, "DELETE") ) - } - private def extractOperationFromGroupedByPath(grouped: List[EnrichedRouteRepresentation[_, _]], operation: String): Option[Operation] = { + private def extractOperationFromGroupedByPath(grouped: List[EnrichedRouteRepresentation[_, _]], operation: String): Option[Operation] = grouped .find(_.routeRepresentation.method.toUpperCase == operation.toUpperCase) .map(routeToOperation) - } - private def routeToOperation(route: EnrichedRouteRepresentation[_, _]): Operation = { + private def routeToOperation(route: EnrichedRouteRepresentation[_, _]): Operation = OperationBuilder.build( summary = route.routeRepresentation.description, description = route.routeRepresentation.extendedDescription @@ -85,7 +72,6 @@ class OpenApiFormatterWorker(jsonSchemaToSwaggerSchemaWorker: JsonSchemaToSwagge responses = routeToApiResponses(route), security = routeToSecurity(route) ) - } private def extractParamsFromPath(path: String): List[Parameter] = { val pattern = """\{(.*?)\}""".r @@ -98,7 +84,7 @@ class OpenApiFormatterWorker(jsonSchemaToSwaggerSchemaWorker: JsonSchemaToSwagge } } - private def queryParamsToParams(parameters: List[RouteParameterRepresentation[_]]): List[Parameter] = { + private def queryParamsToParams(parameters: List[RouteParameterRepresentation[_]]): List[Parameter] = parameters.map { param => val schema = new StringSchema schema.setExample(param.sampleValue) @@ -113,9 +99,8 @@ class OpenApiFormatterWorker(jsonSchemaToSwaggerSchemaWorker: JsonSchemaToSwagge p.setSchema(schema) p } - } - private def headersToParams(parameters: List[RouteHeaderRepresentation]): List[Parameter] = { + private def headersToParams(parameters: List[RouteHeaderRepresentation]): List[Parameter] = parameters.map { header => val p = new Parameter() p.setName(header.name) @@ -124,9 +109,8 @@ class OpenApiFormatterWorker(jsonSchemaToSwaggerSchemaWorker: JsonSchemaToSwagge p.setSchema(new StringSchema) p } - } - private def routeToRequestBody(route: EnrichedRouteRepresentation[_, _]): Option[RequestBody] = { + private def routeToRequestBody(route: EnrichedRouteRepresentation[_, _]): Option[RequestBody] = route.routeRepresentation.request.minimal.jsonString.map { _ => val mt = routeDtoHandlerToMediaType(route.routeRepresentation.request) @@ -135,7 +119,6 @@ class OpenApiFormatterWorker(jsonSchemaToSwaggerSchemaWorker: JsonSchemaToSwagge apiRequest.setContent(new Content().addMediaType("application/json", mt)) apiRequest } - } private def routeToApiResponses(route: EnrichedRouteRepresentation[_, _]): ApiResponses = { val apiResponses = new ApiResponses() @@ -144,19 +127,18 @@ class OpenApiFormatterWorker(jsonSchemaToSwaggerSchemaWorker: JsonSchemaToSwagge .filter(_._1.isDefined) .toList .sortBy(_._1.map(_.intValue())) - .foreach { - case (codeOpt, desc) => - val code = codeOpt.get //get is safe here - val apiResponse = new ApiResponse() + .foreach { case (codeOpt, desc) => + val code = codeOpt.get // get is safe here + val apiResponse = new ApiResponse() - apiResponse.setDescription(desc.map(_.description).mkString("\n")) - if (code.intValue >= 200 && code.intValue < 204) { + apiResponse.setDescription(desc.map(_.description).mkString("\n")) + if (code.intValue >= 200 && code.intValue < 204) { - val mt = routeDtoHandlerToMediaType(route.routeRepresentation.response) - apiResponse.setContent(new Content().addMediaType("application/json", mt)) - } + val mt = routeDtoHandlerToMediaType(route.routeRepresentation.response) + apiResponse.setContent(new Content().addMediaType("application/json", mt)) + } - apiResponses.addApiResponse(code.intValue.toString, apiResponse) + apiResponses.addApiResponse(code.intValue.toString, apiResponse) } apiResponses } @@ -168,8 +150,7 @@ class OpenApiFormatterWorker(jsonSchemaToSwaggerSchemaWorker: JsonSchemaToSwagge security } - private def routeSecurityGroupToSecuritySchemaWithName(route: EnrichedRouteRepresentation[_, _]): List[(String, SecurityScheme)] = { - + private def routeSecurityGroupToSecuritySchemaWithName(route: EnrichedRouteRepresentation[_, _]): List[(String, SecurityScheme)] = route.routeRepresentation.authentication.flatMap(_.list).distinct.map { case RouteSecurity.Bearer(schemaName) => val securityScheme = new SecurityScheme() @@ -201,7 +182,6 @@ class OpenApiFormatterWorker(jsonSchemaToSwaggerSchemaWorker: JsonSchemaToSwagge securityScheme.setName(name) (schemaName, securityScheme) } - } private def routeDtoHandlerToMediaType(dto: RouteDtoHandler[_]): MediaType = { val mt = new MediaType @@ -226,9 +206,8 @@ class OpenApiFormatterWorker(jsonSchemaToSwaggerSchemaWorker: JsonSchemaToSwagge mt } - private def swaggerSchema[T](jsonSchema: JsonSchemaWrapper[T]): Schema[_] = { - jsonSchemaToSwaggerSchemaWorker.convert(jsonSchema.schema) - } + private def swaggerSchema[T](jsonSchema: JsonSchemaWrapper[T]): Schema[_] = + jsonSchemaToSwaggerSchemaWorker.convertMatch(jsonSchema.schema) private def schemaRefName(name: String): String = s"#/components/schemas/${schemaClassName(name)}" diff --git a/formatter-openapi/src/main/scala/pl/iterators/baklava/formatter/openapi/builders/OpenApiBuilder.scala b/formatter-openapi/src/main/scala/pl/iterators/baklava/formatter/openapi/builders/OpenApiBuilder.scala index 8b97a38..d1a4dd5 100644 --- a/formatter-openapi/src/main/scala/pl/iterators/baklava/formatter/openapi/builders/OpenApiBuilder.scala +++ b/formatter-openapi/src/main/scala/pl/iterators/baklava/formatter/openapi/builders/OpenApiBuilder.scala @@ -4,7 +4,11 @@ import io.swagger.v3.oas.models.{Components, OpenAPI, Paths} import io.swagger.v3.oas.models.info.Info object OpenApiBuilder { - def build(info: Info, components: Components, paths: Paths): OpenAPI = { + def build( + info: Info, + components: Components, + paths: Paths + ): OpenAPI = { val openApi = new OpenAPI openApi.setInfo(info) openApi.setPaths(paths) diff --git a/formatter-openapi/src/main/scala/pl/iterators/baklava/formatter/openapi/builders/OperationBuilder.scala b/formatter-openapi/src/main/scala/pl/iterators/baklava/formatter/openapi/builders/OperationBuilder.scala index 0647b61..525690d 100644 --- a/formatter-openapi/src/main/scala/pl/iterators/baklava/formatter/openapi/builders/OperationBuilder.scala +++ b/formatter-openapi/src/main/scala/pl/iterators/baklava/formatter/openapi/builders/OperationBuilder.scala @@ -5,16 +5,16 @@ import io.swagger.v3.oas.models.parameters.{Parameter, RequestBody} import io.swagger.v3.oas.models.responses.ApiResponses import io.swagger.v3.oas.models.security.SecurityRequirement -import scala.collection.JavaConverters._ +import scala.jdk.CollectionConverters._ object OperationBuilder { def build( - summary: String, - description: String, - parameters: List[Parameter], - requestBody: Option[RequestBody], - responses: ApiResponses, - security: List[SecurityRequirement] + summary: String, + description: String, + parameters: List[Parameter], + requestBody: Option[RequestBody], + responses: ApiResponses, + security: List[SecurityRequirement] ): Operation = { val operation = new Operation() operation.setSummary(summary) diff --git a/formatter-openapi/src/main/scala/pl/iterators/baklava/formatter/openapi/builders/PathItemBuilder.scala b/formatter-openapi/src/main/scala/pl/iterators/baklava/formatter/openapi/builders/PathItemBuilder.scala index e87edae..22bfd5c 100644 --- a/formatter-openapi/src/main/scala/pl/iterators/baklava/formatter/openapi/builders/PathItemBuilder.scala +++ b/formatter-openapi/src/main/scala/pl/iterators/baklava/formatter/openapi/builders/PathItemBuilder.scala @@ -5,12 +5,12 @@ import io.swagger.v3.oas.models.parameters.Parameter object PathItemBuilder { def build( - parameters: List[Parameter], - get: Option[Operation], - post: Option[Operation], - patch: Option[Operation], - put: Option[Operation], - delete: Option[Operation] + parameters: List[Parameter], + get: Option[Operation], + post: Option[Operation], + patch: Option[Operation], + put: Option[Operation], + delete: Option[Operation] ): PathItem = { val pathItem = new PathItem diff --git a/formatter-openapi/src/test/scala/pl/iterators/baklava/formatter/OpenApiFormatterWorkerSpec.scala b/formatter-openapi/src/test/scala/pl/iterators/baklava/formatter/OpenApiFormatterWorkerSpec.scala index da1b22c..bc03b37 100644 --- a/formatter-openapi/src/test/scala/pl/iterators/baklava/formatter/OpenApiFormatterWorkerSpec.scala +++ b/formatter-openapi/src/test/scala/pl/iterators/baklava/formatter/OpenApiFormatterWorkerSpec.scala @@ -12,7 +12,7 @@ import pl.iterators.kebs.jsonschema.{KebsJsonSchema, KebsJsonSchemaPredefs} import pl.iterators.kebs.scalacheck.{KebsArbitraryPredefs, KebsScalacheckGenerators} import spray.json._ -import scala.collection.JavaConverters._ +import scala.jdk.CollectionConverters._ object TestData { case class Path1Output(p1Int: Int, p1String: String) @@ -49,38 +49,14 @@ class OpenApiFormatterWorkerSpec extends Specification { "properly split groups paths" in new TestCase { val input = List( - EnrichedRouteRepresentation( - RouteRepresentation[Unit, Unit]("summary 1", "GET", "/path1"), - Nil - ), - EnrichedRouteRepresentation( - RouteRepresentation[Unit, Unit]("summary 2", "POST", "/path1"), - Nil - ), - EnrichedRouteRepresentation( - RouteRepresentation[Unit, Unit]("summary 3", "GET", "/path2/abc"), - Nil - ), - EnrichedRouteRepresentation( - RouteRepresentation[Unit, Unit]("summary 4", "POST", "/path2/abc"), - Nil - ), - EnrichedRouteRepresentation( - RouteRepresentation[Unit, Unit]("summary 5", "PATCH", "/path2/abc"), - Nil - ), - EnrichedRouteRepresentation( - RouteRepresentation[Unit, Unit]("summary 6", "DELETE", "/path2/abc"), - Nil - ), - EnrichedRouteRepresentation( - RouteRepresentation[Unit, Unit]("summary 7", "PUT", "/path2/abc"), - Nil - ), - EnrichedRouteRepresentation( - RouteRepresentation[Unit, Unit]("summary 8", "PUT", "/abc/path3"), - Nil - ), + EnrichedRouteRepresentation(RouteRepresentation[Unit, Unit]("summary 1", "GET", "/path1"), Nil), + EnrichedRouteRepresentation(RouteRepresentation[Unit, Unit]("summary 2", "POST", "/path1"), Nil), + EnrichedRouteRepresentation(RouteRepresentation[Unit, Unit]("summary 3", "GET", "/path2/abc"), Nil), + EnrichedRouteRepresentation(RouteRepresentation[Unit, Unit]("summary 4", "POST", "/path2/abc"), Nil), + EnrichedRouteRepresentation(RouteRepresentation[Unit, Unit]("summary 5", "PATCH", "/path2/abc"), Nil), + EnrichedRouteRepresentation(RouteRepresentation[Unit, Unit]("summary 6", "DELETE", "/path2/abc"), Nil), + EnrichedRouteRepresentation(RouteRepresentation[Unit, Unit]("summary 7", "PUT", "/path2/abc"), Nil), + EnrichedRouteRepresentation(RouteRepresentation[Unit, Unit]("summary 8", "PUT", "/abc/path3"), Nil) ) val openApi = worker.generateOpenApi(input) @@ -137,18 +113,9 @@ class OpenApiFormatterWorkerSpec extends Specification { "properly pass schema refs for input and output classes" in new TestCase { val input = List( - EnrichedRouteRepresentation( - RouteRepresentation[Unit, TestData.Path1Output]("summary 1", "GET", "/path1"), - List("Ok") - ), - EnrichedRouteRepresentation( - RouteRepresentation[TestData.Path2Input, Unit]("summary 2", "PUT", "/path2"), - List("Ok") - ), - EnrichedRouteRepresentation( - RouteRepresentation[TestData.Path3Input, TestData.Path3Output]("summary 3", "POST", "/path3"), - List("Ok") - ) + EnrichedRouteRepresentation(RouteRepresentation[Unit, TestData.Path1Output]("summary 1", "GET", "/path1"), List("Ok")), + EnrichedRouteRepresentation(RouteRepresentation[TestData.Path2Input, Unit]("summary 2", "PUT", "/path2"), List("Ok")), + EnrichedRouteRepresentation(RouteRepresentation[TestData.Path3Input, TestData.Path3Output]("summary 3", "POST", "/path3"), List("Ok")) ) val openApi = worker.generateOpenApi(input) @@ -184,13 +151,13 @@ class OpenApiFormatterWorkerSpec extends Specification { val schemas = openApi.getComponents.getSchemas schemas.get("pl.iterators.baklava.formatter.TestData.Path1Output") shouldEqual - converter.convert(genericJsonSchemaWrapper[TestData.Path1Output].schema) + converter.convertMatch(genericJsonSchemaWrapper[TestData.Path1Output].schema) schemas.get("pl.iterators.baklava.formatter.TestData.Path2Input") shouldEqual - converter.convert(genericJsonSchemaWrapper[TestData.Path2Input].schema) + converter.convertMatch(genericJsonSchemaWrapper[TestData.Path2Input].schema) schemas.get("pl.iterators.baklava.formatter.TestData.Path3Input") shouldEqual - converter.convert(genericJsonSchemaWrapper[TestData.Path3Input].schema) + converter.convertMatch(genericJsonSchemaWrapper[TestData.Path3Input].schema) schemas.get("pl.iterators.baklava.formatter.TestData.Path3Output") shouldEqual - converter.convert(genericJsonSchemaWrapper[TestData.Path3Output].schema) + converter.convertMatch(genericJsonSchemaWrapper[TestData.Path3Output].schema) } "properly pass authentication details" in new TestCase { @@ -210,20 +177,23 @@ class OpenApiFormatterWorkerSpec extends Specification { ) val input3 = List( EnrichedRouteRepresentation( - RouteRepresentation[Unit, TestData.Path1Output]("summary 1", - "GET", - "/path1", - authentication = List(RouteSecurity.Bearer(), RouteSecurity.Basic())), + RouteRepresentation[Unit, TestData.Path1Output]( + "summary 1", + "GET", + "/path1", + authentication = List(RouteSecurity.Bearer(), RouteSecurity.Basic()) + ), List("Ok") ) ) val input4 = List( EnrichedRouteRepresentation( - RouteRepresentation[Unit, TestData.Path1Output]("summary 1", - "GET", - "/path1", - authentication = - List(RouteSecurity.Bearer(), RouteSecurity.Bearer("bearerAuth2"))), + RouteRepresentation[Unit, TestData.Path1Output]( + "summary 1", + "GET", + "/path1", + authentication = List(RouteSecurity.Bearer(), RouteSecurity.Bearer("bearerAuth2")) + ), List("Ok") ) ) @@ -250,11 +220,8 @@ class OpenApiFormatterWorkerSpec extends Specification { "summary 1", "GET", "/path1", - authentication = List( - RouteSecurity.HeaderApiKey("X-API-KEY"), - RouteSecurity.QueryApiKey("api_key"), - RouteSecurity.CookieApiKey("X-COOKIE-KEY-KEY") - ) + authentication = + List(RouteSecurity.HeaderApiKey("X-API-KEY"), RouteSecurity.QueryApiKey("api_key"), RouteSecurity.CookieApiKey("X-COOKIE-KEY-KEY")) ), List("Ok") ) diff --git a/formatter-openapi/src/test/scala/pl/iterators/baklava/formatter/openapi/JsonSchemaToSwaggerSchemaWorkerSpec.scala b/formatter-openapi/src/test/scala/pl/iterators/baklava/formatter/openapi/JsonSchemaToSwaggerSchemaWorkerSpec.scala index c06610c..b2a8c73 100644 --- a/formatter-openapi/src/test/scala/pl/iterators/baklava/formatter/openapi/JsonSchemaToSwaggerSchemaWorkerSpec.scala +++ b/formatter-openapi/src/test/scala/pl/iterators/baklava/formatter/openapi/JsonSchemaToSwaggerSchemaWorkerSpec.scala @@ -4,7 +4,7 @@ import com.github.andyglow.json.Value import io.swagger.v3.oas.models.{media => swagger} import org.specs2.mutable.Specification import java.math.{BigDecimal => JavaBigDecimal} -import scala.collection.JavaConverters._ +import scala.jdk.CollectionConverters._ class JsonSchemaToSwaggerSchemaWorkerSpec extends Specification { @@ -18,12 +18,12 @@ class JsonSchemaToSwaggerSchemaWorkerSpec extends Specification { val input2 = new json.Schema.allof(Set(inner2, inner1)) val input3 = new json.Schema.allof(Set.empty) - val output1 = converter.convert(input1) - val output2 = converter.convert(input2) - val output3 = converter.convert(input3) + val output1 = converter.convertMatch(input1) + val output2 = converter.convertMatch(input2) + val output3 = converter.convertMatch(input3) - output1 shouldEqual converter.convert(inner1) - output2 shouldEqual converter.convert(inner2) + output1 shouldEqual converter.convertMatch(inner1) + output2 shouldEqual converter.convertMatch(inner2) output3 shouldEqual new swagger.Schema[Unit]() } @@ -31,8 +31,8 @@ class JsonSchemaToSwaggerSchemaWorkerSpec extends Specification { val input1 = new json.Schema.array[Boolean, List](json.Schema.boolean) val input2 = new json.Schema.array[Double, List](json.Schema.number[Double]) - val output1 = converter.convert(input1) - val output2 = converter.convert(input2) + val output1 = converter.convertMatch(input1) + val output2 = converter.convertMatch(input2) output1 should haveClass[swagger.ArraySchema] output2 should haveClass[swagger.ArraySchema] @@ -47,9 +47,10 @@ class JsonSchemaToSwaggerSchemaWorkerSpec extends Specification { json.Schema.`object`.Field("sampleString", json.Schema.string, true), json.Schema.`object`.Field("sampleInteger", json.Schema.integer, false), json.Schema.`object`.Field("sampleBoolean", json.Schema.boolean, true) - )) + ) + ) - val output = converter.convert(input) + val output = converter.convertMatch(input) output should haveClass[swagger.ArraySchema] val outputInner = output.asInstanceOf[swagger.ArraySchema].getItems @@ -65,7 +66,7 @@ class JsonSchemaToSwaggerSchemaWorkerSpec extends Specification { "should convert array schema properly (array contains dict inside)" in { val input = json.Schema.array(new json.Schema.dictionary(json.Schema.string)) - val output = converter.convert(input) + val output = converter.convertMatch(input) output should haveClass[swagger.ArraySchema] val outputInner = output.asInstanceOf[swagger.ArraySchema].getItems @@ -77,7 +78,7 @@ class JsonSchemaToSwaggerSchemaWorkerSpec extends Specification { "should convert boolean schema properly" in { val input = json.Schema.boolean - val output = converter.convert(input) + val output = converter.convertMatch(input) output shouldEqual new swagger.BooleanSchema } @@ -86,8 +87,8 @@ class JsonSchemaToSwaggerSchemaWorkerSpec extends Specification { val input1 = new json.Schema.`def`("sig", json.Schema.boolean) val input2 = new json.Schema.`def`("sig", new json.Schema.array[Float, List](json.Schema.number[Float])) - val output1 = converter.convert(input1) - val output2 = converter.convert(input2) + val output1 = converter.convertMatch(input1) + val output2 = converter.convertMatch(input2) output1 shouldEqual new swagger.BooleanSchema output2 should haveClass[swagger.ArraySchema] @@ -99,9 +100,9 @@ class JsonSchemaToSwaggerSchemaWorkerSpec extends Specification { val input2 = new json.Schema.dictionary(json.Schema.number[BigDecimal]) val input3 = new json.Schema.dictionary(json.Schema.string) - val output1 = converter.convert(input1) - val output2 = converter.convert(input2) - val output3 = converter.convert(input3) + val output1 = converter.convertMatch(input1) + val output2 = converter.convertMatch(input2) + val output3 = converter.convertMatch(input3) output1 should haveClass[swagger.ObjectSchema] output2 should haveClass[swagger.ObjectSchema] @@ -124,11 +125,11 @@ class JsonSchemaToSwaggerSchemaWorkerSpec extends Specification { val input = new json.Schema.dictionary(innerInput) val arrayInput = new json.Schema.dictionary(arrayInnerInput) - val output = converter.convert(input) - output.asInstanceOf[swagger.ObjectSchema].getProperties.asScala shouldEqual Map("^.*$" -> converter.convert(innerInput)) + val output = converter.convertMatch(input) + output.asInstanceOf[swagger.ObjectSchema].getProperties.asScala shouldEqual Map("^.*$" -> converter.convertMatch(innerInput)) - val arrayOutput = converter.convert(arrayInput) - arrayOutput.asInstanceOf[swagger.ObjectSchema].getProperties.asScala shouldEqual Map("^.*$" -> converter.convert(arrayInnerInput)) + val arrayOutput = converter.convertMatch(arrayInput) + arrayOutput.asInstanceOf[swagger.ObjectSchema].getProperties.asScala shouldEqual Map("^.*$" -> converter.convertMatch(arrayInnerInput)) } "should convert enum schema properly" in { @@ -136,9 +137,9 @@ class JsonSchemaToSwaggerSchemaWorkerSpec extends Specification { val input2 = json.Schema.`enum`(json.Schema.integer, Set(Value.num(1), Value.num(10), Value.num(30))) val input3 = json.Schema.`enum`(json.Schema.number[Double], Set(Value.num(1.123), Value.num(10.1), Value.num(3.2))) - val output1 = converter.convert(input1) - val output2 = converter.convert(input2) - val output3 = converter.convert(input3) + val output1 = converter.convertMatch(input1) + val output2 = converter.convertMatch(input2) + val output3 = converter.convertMatch(input3) output1 should haveClass[swagger.StringSchema] output2 should haveClass[swagger.IntegerSchema] @@ -154,7 +155,7 @@ class JsonSchemaToSwaggerSchemaWorkerSpec extends Specification { "should convert integer schema properly" in { val input = json.Schema.integer - val output = converter.convert(input) + val output = converter.convertMatch(input) output shouldEqual new swagger.IntegerSchema } @@ -162,7 +163,7 @@ class JsonSchemaToSwaggerSchemaWorkerSpec extends Specification { "should convert not schema properly" in { val input = json.Schema.not(json.Schema.integer) - val output = converter.convert(input) + val output = converter.convertMatch(input) output shouldEqual new swagger.Schema[Unit]() } @@ -172,9 +173,9 @@ class JsonSchemaToSwaggerSchemaWorkerSpec extends Specification { val input2 = json.Schema.number[BigDecimal] val input3 = json.Schema.number[Float] - val output1 = converter.convert(input1) - val output2 = converter.convert(input2) - val output3 = converter.convert(input3) + val output1 = converter.convertMatch(input1) + val output2 = converter.convertMatch(input2) + val output3 = converter.convertMatch(input3) output1 shouldEqual new swagger.NumberSchema output2 shouldEqual new swagger.NumberSchema @@ -185,8 +186,8 @@ class JsonSchemaToSwaggerSchemaWorkerSpec extends Specification { val input1 = json.Schema.string val input2 = json.Schema.string(json.Schema.string.Format.uuid) - val output1 = converter.convert(input1) - val output2 = converter.convert(input2) + val output1 = converter.convertMatch(input1) + val output2 = converter.convertMatch(input2) output1 shouldEqual new swagger.StringSchema output2 should haveClass[swagger.StringSchema] @@ -200,7 +201,7 @@ class JsonSchemaToSwaggerSchemaWorkerSpec extends Specification { json.Schema.`object`.Field("sampleBoolean", json.Schema.boolean, true) ) - val output = converter.convert(input) + val output = converter.convertMatch(input) output should haveClass[swagger.ObjectSchema] output.asInstanceOf[swagger.ObjectSchema].getRequired.asScala should @@ -235,10 +236,10 @@ class JsonSchemaToSwaggerSchemaWorkerSpec extends Specification { json.Schema.`object`.Field("innerDict", innerDict, false), json.Schema.`object`.Field("innerDictOfArray", innerDictOfArray, false), json.Schema.`object`.Field("innerDictOfArrayOfObjects", innerDictOfArrayOfObjects, false), - json.Schema.`object`.Field("innerDictOfObjects", innerDictOfObjects, false), + json.Schema.`object`.Field("innerDictOfObjects", innerDictOfObjects, false) ) - val output = converter.convert(input) + val output = converter.convertMatch(input) output should haveClass[swagger.ObjectSchema] output.asInstanceOf[swagger.ObjectSchema].getRequired.asScala should @@ -246,12 +247,12 @@ class JsonSchemaToSwaggerSchemaWorkerSpec extends Specification { val outputProperties = output.getProperties.asScala outputProperties("sampleString") should haveClass[swagger.StringSchema] outputProperties("sampleNumber") should haveClass[swagger.NumberSchema] - outputProperties("innerArray") shouldEqual converter.convert(innerArray) - outputProperties("innerArrayOfObjects") shouldEqual converter.convert(innerArrayOfObjects) - outputProperties("innerDict") shouldEqual converter.convert(innerDict) - outputProperties("innerDictOfArray") shouldEqual converter.convert(innerDictOfArray) - outputProperties("innerDictOfArrayOfObjects") shouldEqual converter.convert(innerDictOfArrayOfObjects) - outputProperties("innerDictOfObjects") shouldEqual converter.convert(innerDictOfObjects) + outputProperties("innerArray") shouldEqual converter.convertMatch(innerArray) + outputProperties("innerArrayOfObjects") shouldEqual converter.convertMatch(innerArrayOfObjects) + outputProperties("innerDict") shouldEqual converter.convertMatch(innerDict) + outputProperties("innerDictOfArray") shouldEqual converter.convertMatch(innerDictOfArray) + outputProperties("innerDictOfArrayOfObjects") shouldEqual converter.convertMatch(innerDictOfArrayOfObjects) + outputProperties("innerDictOfObjects") shouldEqual converter.convertMatch(innerDictOfObjects) } "should convert oneof schema properly" in { @@ -262,19 +263,19 @@ class JsonSchemaToSwaggerSchemaWorkerSpec extends Specification { val input2 = new json.Schema.oneof(Set(inner2, inner1)) val input3 = new json.Schema.oneof(Set.empty) - val output1 = converter.convert(input1) - val output2 = converter.convert(input2) - val output3 = converter.convert(input3) + val output1 = converter.convertMatch(input1) + val output2 = converter.convertMatch(input2) + val output3 = converter.convertMatch(input3) - output1 shouldEqual converter.convert(inner1) - output2 shouldEqual converter.convert(inner2) + output1 shouldEqual converter.convertMatch(inner1) + output2 shouldEqual converter.convertMatch(inner2) output3 shouldEqual new swagger.Schema[Unit]() } "should convert ref schema properly" in { val input = json.Schema.ref("ref") - val output = converter.convert(input) + val output = converter.convertMatch(input) output shouldEqual new swagger.Schema[Unit]() } @@ -288,13 +289,13 @@ class JsonSchemaToSwaggerSchemaWorkerSpec extends Specification { val input2 = json.Schema.`value-class`[String, BigDecimal](inner2) val input3 = json.Schema.`value-class`[Float, String](inner3) - val output1 = converter.convert(input1) - val output2 = converter.convert(input2) - val output3 = converter.convert(input3) + val output1 = converter.convertMatch(input1) + val output2 = converter.convertMatch(input2) + val output3 = converter.convertMatch(input3) - output1 shouldEqual converter.convert(inner1) - output2 shouldEqual converter.convert(inner2) - output3 shouldEqual converter.convert(inner3) + output1 shouldEqual converter.convertMatch(inner1) + output2 shouldEqual converter.convertMatch(inner2) + output3 shouldEqual converter.convertMatch(inner3) } } diff --git a/formatter/src/main/scala/pl/iterators/baklava/formatter/SimpleDocsFormatter.scala b/formatter/src/main/scala/pl/iterators/baklava/formatter/SimpleDocsFormatter.scala index 046db5b..bc3d3f8 100644 --- a/formatter/src/main/scala/pl/iterators/baklava/formatter/SimpleDocsFormatter.scala +++ b/formatter/src/main/scala/pl/iterators/baklava/formatter/SimpleDocsFormatter.scala @@ -122,10 +122,10 @@ class SimpleDocsFormatter extends Formatter { s"AUTHENTICATION" }, Some(s"BEHAVIOUR${p.enrichDescriptions - .map { enrichedDescription => - s"${enrichedDescription.description} ${enrichedDescription.statusCodeOpt.map(c => s"-> [$c]").getOrElse("")}" - } - .mkString("
")}"), + .map { enrichedDescription => + s"${enrichedDescription.description} ${enrichedDescription.statusCodeOpt.map(c => s"-> [$c]").getOrElse("")}" + } + .mkString("
")}"), Some(s"STATUS CODES${statusCodes.mkString("
")}"), Option.when(r.parameters.nonEmpty) { s"PARAMETERS" + @@ -134,9 +134,11 @@ class SimpleDocsFormatter extends Formatter { s"ROUTE WITH MINIMAL PARAMS${r.routePathWithRequiredParameters}" + s"ROUTE WITH ALL PARAMS${r.routePathWithAllParameters}" }, - Option.when(r.headers.nonEmpty)(s"HEADERS" + - s"${r.headers.map(h => s"${h.name}${Option.when(h.required)("*").getOrElse("")}").mkString("
")}" + - s""), + Option.when(r.headers.nonEmpty)( + s"HEADERS" + + s"${r.headers.map(h => s"${h.name}${Option.when(h.required)("*").getOrElse("")}").mkString("
")}" + + s"" + ), r.request.scalaClassOpt.map(s => s"REQUEST SCALA TYPE
$s
"), r.request.minimal.jsonString.map(s => s"REQUEST MINIMAL JSON
$s
"), r.request.maximal.jsonString.map(s => s"REQUEST MAXIMAL JSON
$s
"), @@ -144,7 +146,7 @@ class SimpleDocsFormatter extends Formatter { r.response.scalaClassOpt.map(s => s"RESPONSE SCALA TYPE
$s
"), r.response.minimal.jsonString.map(s => s"RESPONSE MINIMAL JSON
$s
"), r.response.maximal.jsonString.map(s => s"RESPONSE MAXIMAL JSON
$s
"), - r.response.schema.map(s => s"RESPONSE SCHEMA
${printSchema(s)}
"), + r.response.schema.map(s => s"RESPONSE SCHEMA
${printSchema(s)}
") ).flatten.mkString("\n") + "" } diff --git a/formatter/src/main/scala/pl/iterators/baklava/formatter/TsFormatter.scala b/formatter/src/main/scala/pl/iterators/baklava/formatter/TsFormatter.scala index 2a1830f..5f7d581 100644 --- a/formatter/src/main/scala/pl/iterators/baklava/formatter/TsFormatter.scala +++ b/formatter/src/main/scala/pl/iterators/baklava/formatter/TsFormatter.scala @@ -43,12 +43,8 @@ trait TsFormatterBase extends Formatter { val headers = generateHeadersInterface(route) val request = generateRequestInterface(route) val response = generateResponseInterface(route) - val configAndApi = generateAxiosConfigAndApi(route, - pathParams.map(_._1), - queryParams.map(_._1), - headers.map(_._1), - request.map(_._1), - response.map(_._1)) + val configAndApi = + generateAxiosConfigAndApi(route, pathParams.map(_._1), queryParams.map(_._1), headers.map(_._1), request.map(_._1), response.map(_._1)) ( s"""/* -- Start of ${route.routeRepresentation.name} -- */ \n""" + @@ -75,16 +71,12 @@ trait TsFormatterBase extends Formatter { name, list .map(i => s""" \"$i\": string;""") - .mkString( - s"interface $name {\n", - "\n", - "\n}\n\n" - ) + .mkString(s"interface $name {\n", "\n", "\n}\n\n") ) } } - private def generateQueryPathParamsInterface(route: EnrichedRouteRepresentation[_, _]): Option[(String, String)] = { + private def generateQueryPathParamsInterface(route: EnrichedRouteRepresentation[_, _]): Option[(String, String)] = Option.when(route.routeRepresentation.parameters.nonEmpty) { val name = s"${className(route)}QueryParams" ( @@ -92,19 +84,14 @@ trait TsFormatterBase extends Formatter { route.routeRepresentation.parameters .map { p => s""" \"${p.name}\"${Option - .when(p.required)("") - .getOrElse("?")}: string;""" + .when(p.required)("") + .getOrElse("?")}: string;""" } - .mkString( - s"interface $name {\n", - "\n", - "\n}\n\n" - ) + .mkString(s"interface $name {\n", "\n", "\n}\n\n") ) } - } - private def generateHeadersInterface(route: EnrichedRouteRepresentation[_, _]): Option[(String, String)] = { + private def generateHeadersInterface(route: EnrichedRouteRepresentation[_, _]): Option[(String, String)] = Option.when(route.routeRepresentation.headers.nonEmpty) { val name = s"${className(route)}Headers" ( @@ -112,47 +99,39 @@ trait TsFormatterBase extends Formatter { route.routeRepresentation.headers .map { p => s""" \"${p.name}\"${Option - .when(p.required)("") - .getOrElse("?")}: string;""" + .when(p.required)("") + .getOrElse("?")}: string;""" } - .mkString( - s"interface $name {\n", - "\n", - "\n}\n\n" - ) + .mkString(s"interface $name {\n", "\n", "\n}\n\n") ) } - } - private def generateRequestInterface(route: EnrichedRouteRepresentation[_, _]): Option[(String, String)] = { + private def generateRequestInterface(route: EnrichedRouteRepresentation[_, _]): Option[(String, String)] = Option.when(!route.routeRepresentation.request.isUnit) { val name = s"${className(route)}Request" generateClassRepresentation(name, route.routeRepresentation.requestJsonSchemaWrapper.schema) } - } - private def generateResponseInterface(route: EnrichedRouteRepresentation[_, _]): Option[(String, String)] = { + private def generateResponseInterface(route: EnrichedRouteRepresentation[_, _]): Option[(String, String)] = Option.when(!route.routeRepresentation.response.isUnit) { val name = s"${className(route)}Response" generateClassRepresentation(name, route.routeRepresentation.responseJsonSchemaWrapper.schema) } - } private def generateAxiosConfigAndApi( - route: EnrichedRouteRepresentation[_, _], - pathParams: Option[String], - queryParams: Option[String], - headers: Option[String], - request: Option[String], - response: Option[String] + route: EnrichedRouteRepresentation[_, _], + pathParams: Option[String], + queryParams: Option[String], + headers: Option[String], + request: Option[String], + response: Option[String] ): (String, String) = { - val allFunctionParamsWithNames = ( + val allFunctionParamsWithNames = pathParams.map(p => ("pathParams", p)) :: queryParams.map(p => ("queryParams", p)) :: headers.map(p => ("headers", p)) :: request.map(p => ("request", p)) :: Nil - ) val functionParamsNamesAndValuesString = allFunctionParamsWithNames.flatten .map(p => s"${p._1}: ${p._2}") @@ -170,8 +149,8 @@ trait TsFormatterBase extends Formatter { route.enrichDescriptions .map { enrichedDescription => s" ${enrichedDescription.description} ${enrichedDescription.statusCodeOpt - .map(c => s"-> [$c]") - .getOrElse("")}" + .map(c => s"-> [$c]") + .getOrElse("")}" } .mkString("\n") @@ -190,7 +169,7 @@ trait TsFormatterBase extends Formatter { | $description | */ | ${methodName(route)}: function($functionParamsNamesAndValuesString): Promise<${response - .getOrElse("{}")}> { + .getOrElse("{}")}> { | return axios(${methodName(route)}AxiosConfig($functionParamsNamesString)) | .then(function (response: any) { | return response.data; @@ -199,7 +178,7 @@ trait TsFormatterBase extends Formatter { ) } - private def generateClassRepresentation(name: String, jsonSchema: json.Schema[_]): (String, String) = { + private def generateClassRepresentation(name: String, jsonSchema: json.Schema[_]): (String, String) = jsonSchema.jsonType match { case "boolean" => ("boolean", "") @@ -243,8 +222,8 @@ trait TsFormatterBase extends Formatter { name, s"""interface $name { |${fields - .map(f => s""" "${f._1}": ${f._2._1};""") - .mkString("\n")} + .map(f => s""" "${f._1}": ${f._2._1};""") + .mkString("\n")} |} |""".stripMargin + fields.map(_._2._2).mkString("\n") ) @@ -252,7 +231,6 @@ trait TsFormatterBase extends Formatter { case _ => ("", "") } - } private def className(route: EnrichedRouteRepresentation[_, _]): String = { val methodPart = route.routeRepresentation.method.toLowerCase.capitalize @@ -268,14 +246,13 @@ trait TsFormatterBase extends Formatter { } class TsFormatter extends TsFormatterBase { - override protected def pathName(path: String): String = { + override protected def pathName(path: String): String = path .replaceAll("\\{", "") .replaceAll("\\}", "") .split("/") .map(_.toLowerCase.capitalize) .mkString("") - } } class TsStrictFormatter extends TsFormatterBase { @@ -300,7 +277,7 @@ class TsStrictFormatter extends TsFormatterBase { .mkString("") } - private def pluralToSingular(word: String): String = { + private def pluralToSingular(word: String): String = if (word.endsWith("es")) { word.stripSuffix("es") } else if (word.endsWith("s")) { @@ -308,5 +285,4 @@ class TsStrictFormatter extends TsFormatterBase { } else { word } - } } diff --git a/generator/src/main/scala/pl/iterators/baklava/generator/Generator.scala b/generator/src/main/scala/pl/iterators/baklava/generator/Generator.scala index ac90f95..381f0b6 100644 --- a/generator/src/main/scala/pl/iterators/baklava/generator/Generator.scala +++ b/generator/src/main/scala/pl/iterators/baklava/generator/Generator.scala @@ -4,11 +4,16 @@ import org.reflections.Reflections import pl.iterators.baklava.core.fetchers.Fetcher import pl.iterators.baklava.formatter.Formatter -import scala.collection.JavaConverters.asScalaSetConverter +import scala.jdk.CollectionConverters._ object Generator { - def generate(mainPackageName: String, outputDir: String, fetcherName: String, formatterNames: Seq[String]): Unit = { + def generate( + mainPackageName: String, + outputDir: String, + fetcherName: String, + formatterNames: Seq[String] + ): Unit = { val reflections = new Reflections(mainPackageName, "pl.iterators.baklava") val fetcher = dynamicallyLoad(reflections, fetcherName, classOf[Fetcher]) @@ -20,7 +25,11 @@ object Generator { } } - private def dynamicallyLoad[T](reflections: Reflections, className: String, classOf: Class[T]): T = { + private def dynamicallyLoad[T]( + reflections: Reflections, + className: String, + classOf: Class[T] + ): T = reflections .getSubTypesOf(classOf) .asScala @@ -29,5 +38,4 @@ object Generator { specClazz.getConstructor().newInstance() } .getOrElse(sys.error(s"Unable to find class with name $className in classPath")) - } } diff --git a/generator/src/main/scala/pl/iterators/baklava/generator/Main.scala b/generator/src/main/scala/pl/iterators/baklava/generator/Main.scala index 4346f36..f99eb37 100644 --- a/generator/src/main/scala/pl/iterators/baklava/generator/Main.scala +++ b/generator/src/main/scala/pl/iterators/baklava/generator/Main.scala @@ -2,5 +2,5 @@ package pl.iterators.baklava.generator object Main { def main(args: Array[String]): Unit = - Generator.generate(args(0), args(1), args(2), args.slice(3, args.length)) + Generator.generate(args(0), args(1), args(2), args.slice(3, args.length).toIndexedSeq) } diff --git a/generator/src/test/scala/pl/iterators/baklava/generator/GeneratorCirceSpec.scala b/generator/src/test/scala/pl/iterators/baklava/generator/GeneratorCirceSpec.scala index 3ba8d2b..74cae9b 100644 --- a/generator/src/test/scala/pl/iterators/baklava/generator/GeneratorCirceSpec.scala +++ b/generator/src/test/scala/pl/iterators/baklava/generator/GeneratorCirceSpec.scala @@ -37,18 +37,9 @@ class CirceTestFetcher CirceStaticTestState.testFetcherLastMainPackageName = mainPackageName CirceStaticTestState.testFetcherReturnList = List( - EnrichedRouteRepresentation( - RouteRepresentation[Unit, Unit](Random.nextString(10), Random.nextString(10), Random.nextString(10)), - Nil - ), - EnrichedRouteRepresentation( - RouteRepresentation[Unit, Unit](Random.nextString(10), Random.nextString(10), Random.nextString(10)), - Nil - ), - EnrichedRouteRepresentation( - RouteRepresentation[Unit, Unit](Random.nextString(10), Random.nextString(10), Random.nextString(10)), - Nil - ) + EnrichedRouteRepresentation(RouteRepresentation[Unit, Unit](Random.nextString(10), Random.nextString(10), Random.nextString(10)), Nil), + EnrichedRouteRepresentation(RouteRepresentation[Unit, Unit](Random.nextString(10), Random.nextString(10), Random.nextString(10)), Nil), + EnrichedRouteRepresentation(RouteRepresentation[Unit, Unit](Random.nextString(10), Random.nextString(10), Random.nextString(10)), Nil) ) CirceStaticTestState.testFetcherReturnList diff --git a/generator/src/test/scala/pl/iterators/baklava/generator/GeneratorSpraySpec.scala b/generator/src/test/scala/pl/iterators/baklava/generator/GeneratorSpraySpec.scala index fc33a09..872f028 100644 --- a/generator/src/test/scala/pl/iterators/baklava/generator/GeneratorSpraySpec.scala +++ b/generator/src/test/scala/pl/iterators/baklava/generator/GeneratorSpraySpec.scala @@ -39,18 +39,9 @@ class SprayTestFetcher SprayStaticTestState.testFetcherLastMainPackageName = mainPackageName SprayStaticTestState.testFetcherReturnList = List( - EnrichedRouteRepresentation( - RouteRepresentation[Unit, Unit](Random.nextString(10), Random.nextString(10), Random.nextString(10)), - Nil - ), - EnrichedRouteRepresentation( - RouteRepresentation[Unit, Unit](Random.nextString(10), Random.nextString(10), Random.nextString(10)), - Nil - ), - EnrichedRouteRepresentation( - RouteRepresentation[Unit, Unit](Random.nextString(10), Random.nextString(10), Random.nextString(10)), - Nil - ) + EnrichedRouteRepresentation(RouteRepresentation[Unit, Unit](Random.nextString(10), Random.nextString(10), Random.nextString(10)), Nil), + EnrichedRouteRepresentation(RouteRepresentation[Unit, Unit](Random.nextString(10), Random.nextString(10), Random.nextString(10)), Nil), + EnrichedRouteRepresentation(RouteRepresentation[Unit, Unit](Random.nextString(10), Random.nextString(10), Random.nextString(10)), Nil) ) SprayStaticTestState.testFetcherReturnList diff --git a/http4s-stir-routes/src/main/scala/pl/iterators/baklava/routes/BaklavaRoutes.scala b/http4s-stir-routes/src/main/scala/pl/iterators/baklava/routes/BaklavaRoutes.scala index 284af5c..293f45b 100644 --- a/http4s-stir-routes/src/main/scala/pl/iterators/baklava/routes/BaklavaRoutes.scala +++ b/http4s-stir-routes/src/main/scala/pl/iterators/baklava/routes/BaklavaRoutes.scala @@ -27,7 +27,8 @@ object BaklavaRoutes { } ~ pathPrefix("swagger") { get(complete(swaggerRedirectHttpResponse)) } - } else + } + else RouteDirectives.reject } @@ -55,11 +56,10 @@ object BaklavaRoutes { private def swaggerRedirectHttpResponse(implicit internalConfig: BaklavaRoutes.Config) = { val swaggerUiUrl = s"${internalConfig.publicPathPrefix}swagger-ui/3.40.0/index.html" val swaggerDocsUrl = s"${internalConfig.publicPathPrefix}openapi" - Response[IO](status = Status.SeeOther, - headers = Headers(Location(Uri.unsafeFromString(s"$swaggerUiUrl?url=$swaggerDocsUrl&layout=BaseLayout")))) + Response[IO](status = Status.SeeOther, headers = Headers(Location(Uri.unsafeFromString(s"$swaggerUiUrl?url=$swaggerDocsUrl&layout=BaseLayout")))) } - private lazy val swaggerWebJar: Route = { + private lazy val swaggerWebJar: Route = extractUnmatchedPath { path => Try((new WebJarAssetLocator).getFullPath("swagger-ui", path.toString)) match { case Success(fullPath) => @@ -70,14 +70,14 @@ object BaklavaRoutes { failWith(e) } } - } - private case class Config(enabled: Boolean, - basicAuthUser: Option[String], - basicAuthPassword: Option[String], - fileSystemPath: String, - publicPathPrefix: String, - apiPublicPathPrefix: String) + private case class Config( + enabled: Boolean, + basicAuthUser: Option[String], + basicAuthPassword: Option[String], + fileSystemPath: String, + publicPathPrefix: String, + apiPublicPathPrefix: String) private object Config { def apply(config: com.typesafe.config.Config): Config = { diff --git a/pekko-http-routes/src/main/resources/reference.conf b/pekko-http-routes/src/main/resources/reference.conf new file mode 100644 index 0000000..d94da98 --- /dev/null +++ b/pekko-http-routes/src/main/resources/reference.conf @@ -0,0 +1,20 @@ +baklavaRoutes { + enabled = "true" + enabled = ${?BAKLAVA_ROUTES_ENABLED} + + #Override this to set http basic auth for baklava routes + basicAuthUser = ${?BAKLAVA_ROUTES_BASIC_AUTH_USER} + basicAuthPassword = ${?BAKLAVA_ROUTES_BASIC_AUTH_PASSWORD} + + #Filesystem path where output of baklava is stored + fileSystemPath = "./target/baklava" + fileSystemPath = ${?BAKLAVA_ROUTES_FILESYSTEM_PATH} + + #HTTP serve prefix of baklava resources + publicPathPrefix = "/" + publicPathPrefix = ${?BAKLAVA_ROUTES_PUBLIC_PATH_PREFIX} + + #API prefix + apiPublicPathPrefix = "/v1" + apiPublicPathPrefix = ${?BAKLAVA_ROUTES_API_PUBLIC_PATH_PREFIX} +} diff --git a/pekko-http-routes/src/main/scala/pl/iterators/baklava/routes/BaklavaRoutes.scala b/pekko-http-routes/src/main/scala/pl/iterators/baklava/routes/BaklavaRoutes.scala new file mode 100644 index 0000000..10cf9af --- /dev/null +++ b/pekko-http-routes/src/main/scala/pl/iterators/baklava/routes/BaklavaRoutes.scala @@ -0,0 +1,94 @@ +package pl.iterators.baklava.routes + +import org.apache.pekko.http.scaladsl.model.headers.Location +import org.apache.pekko.http.scaladsl.model.{HttpResponse, StatusCodes} +import org.apache.pekko.http.scaladsl.server.Directives._ +import org.apache.pekko.http.scaladsl.server.Route +import org.apache.pekko.http.scaladsl.server.directives.{Credentials, RouteDirectives} +import org.webjars.WebJarAssetLocator + +import scala.io.Source +import scala.util.{Failure, Success, Try} + +object BaklavaRoutes { + def routes(config: com.typesafe.config.Config): Route = { + implicit val internalConfig: BaklavaRoutes.Config = BaklavaRoutes.Config(config) + if (internalConfig.enabled) + authenticateBasic("docs", basicAuthOpt) { _ => + pathPrefix("docs") { + pathSingleSlash { + getFromFile(s"${internalConfig.fileSystemPath}/simple/index.html") + } ~ getFromDirectory(s"${internalConfig.fileSystemPath}/simple") + } ~ path("openapi") { + complete(openApiFileContent) + } ~ pathPrefix("swagger-ui") { + swaggerWebJar + } ~ pathPrefix("swagger") { + get(complete(swaggerRedirectHttpResponse)) + } + } + else + RouteDirectives.reject + } + + private def basicAuthOpt(credentials: Credentials)(implicit internalConfig: BaklavaRoutes.Config): Option[String] = + (internalConfig.basicAuthUser, internalConfig.basicAuthPassword) match { + case (Some(user), Some(password)) => + credentials match { + case p @ Credentials.Provided(id) if id == user && p.verify(password) => Some(id) + case _ => None + } + case _ => Some("") + } + + private def openApiFileContent(implicit internalConfig: BaklavaRoutes.Config): String = { + val source = Source.fromFile(s"${internalConfig.fileSystemPath}/openapi/openapi.yml") + val lines = source.getLines() + val firstLine = lines.next() + val serverConfig = List("servers:", s" - url: ${internalConfig.apiPublicPathPrefix}") + val tailLines = lines.toList + val content = firstLine :: serverConfig ::: tailLines + source.close() + content.mkString("\n") + } + + private def swaggerRedirectHttpResponse(implicit internalConfig: BaklavaRoutes.Config) = { + val swaggerUiUrl = s"${internalConfig.publicPathPrefix}swagger-ui/3.40.0/index.html" + val swaggerDocsUrl = s"${internalConfig.publicPathPrefix}openapi" + HttpResponse(status = StatusCodes.SeeOther, headers = Location(s"$swaggerUiUrl?url=$swaggerDocsUrl&layout=BaseLayout") :: Nil) + } + + private lazy val swaggerWebJar: Route = + extractUnmatchedPath { path => + Try((new WebJarAssetLocator).getFullPath("swagger-ui", path.toString)) match { + case Success(fullPath) => + getFromResource(fullPath) + case Failure(_: IllegalArgumentException) => + reject + case Failure(e) => + failWith(e) + } + } + + private case class Config( + enabled: Boolean, + basicAuthUser: Option[String], + basicAuthPassword: Option[String], + fileSystemPath: String, + publicPathPrefix: String, + apiPublicPathPrefix: String) + + private object Config { + def apply(config: com.typesafe.config.Config): Config = { + val c = config.getConfig("baklavaRoutes") + Config( + enabled = c.getBoolean("enabled"), + basicAuthUser = Try(c.getString("basicAuthUser")).toOption, + basicAuthPassword = Try(c.getString("basicAuthPassword")).toOption, + fileSystemPath = c.getString("fileSystemPath"), + publicPathPrefix = c.getString("publicPathPrefix"), + apiPublicPathPrefix = c.getString("apiPublicPathPrefix") + ) + } + } +} diff --git a/pekko-http/src/main/scala/pl/iterators/baklava/pekkohttp/PekkoHttpRouteBaklavaSpec.scala b/pekko-http/src/main/scala/pl/iterators/baklava/pekkohttp/PekkoHttpRouteBaklavaSpec.scala new file mode 100644 index 0000000..17a3f5b --- /dev/null +++ b/pekko-http/src/main/scala/pl/iterators/baklava/pekkohttp/PekkoHttpRouteBaklavaSpec.scala @@ -0,0 +1,10 @@ +package pl.iterators.baklava.pekkohttp + +import org.apache.pekko.http.scaladsl.client.RequestBuilding +import org.apache.pekko.http.scaladsl.model.HttpMethods +import pl.iterators.baklava.core.fetchers.RouteBaklavaSpec + +trait PekkoHttpRouteBaklavaSpec extends RouteBaklavaSpec with RequestBuilding { + + lazy val TestRequest = new RequestBuilder(HttpMethods.getForKeyCaseInsensitive(routeRepresentation.method).get) +} diff --git a/project/plugins.sbt b/project/plugins.sbt index 86ee829..1a3855c 100644 --- a/project/plugins.sbt +++ b/project/plugins.sbt @@ -1,2 +1,3 @@ -addSbtPlugin("com.lucidchart" % "sbt-scalafmt" % "1.16") -addSbtPlugin("com.github.sbt" % "sbt-ci-release" % "1.5.10") +addSbtPlugin("org.scalameta" % "sbt-scalafmt" % "2.5.2") +addSbtPlugin("com.timushev.sbt" % "sbt-updates" % "0.6.3") +addSbtPlugin("com.github.sbt" % "sbt-ci-release" % "1.5.10") diff --git a/sbtplugin/src/main/scala/pl/iterators/baklava/sbtplugin/BaklavaSbtPlugin.scala b/sbtplugin/src/main/scala/pl/iterators/baklava/sbtplugin/BaklavaSbtPlugin.scala index a101c09..8abe5e8 100644 --- a/sbtplugin/src/main/scala/pl/iterators/baklava/sbtplugin/BaklavaSbtPlugin.scala +++ b/sbtplugin/src/main/scala/pl/iterators/baklava/sbtplugin/BaklavaSbtPlugin.scala @@ -32,7 +32,7 @@ object BaklavaSbtPlugin extends AutoPlugin { val baklavaFetcher = settingKey[Fetchers.Fetcher]("Selected fetcher") val baklavaFormatters = settingKey[Seq[Formatters.Formatter]]("Selected formatters") - //tasks + // tasks val baklavaGenerate = taskKey[Unit]("Generate documentation using baklava") val baklavaClean = taskKey[Unit]("Clean baklava resources") } diff --git a/scalatest/src/main/scala/pl/iterators/baklava/fetcher/ScalatestFetcher.scala b/scalatest/src/main/scala/pl/iterators/baklava/fetcher/ScalatestFetcher.scala index 4dc01bd..2ec14ff 100644 --- a/scalatest/src/main/scala/pl/iterators/baklava/fetcher/ScalatestFetcher.scala +++ b/scalatest/src/main/scala/pl/iterators/baklava/fetcher/ScalatestFetcher.scala @@ -4,7 +4,7 @@ import org.reflections.Reflections import pl.iterators.baklava.core.fetchers.Fetcher import pl.iterators.baklava.core.model.{EnrichedRouteRepresentation, RouteRepresentation} -import scala.collection.JavaConverters.asScalaSetConverter +import scala.jdk.CollectionConverters._ class ScalatestFetcher extends Fetcher { override def fetch(reflections: Reflections, mainPackageName: String): List[EnrichedRouteRepresentation[_, _]] = { diff --git a/scalatest/src/test/scala/pl/iterators/baklava/fetcher/AkkaHttpScalatestFetcherSpec.scala b/scalatest/src/test/scala/pl/iterators/baklava/fetcher/AkkaHttpScalatestFetcherSpec.scala index 9432098..f796e7e 100644 --- a/scalatest/src/test/scala/pl/iterators/baklava/fetcher/AkkaHttpScalatestFetcherSpec.scala +++ b/scalatest/src/test/scala/pl/iterators/baklava/fetcher/AkkaHttpScalatestFetcherSpec.scala @@ -22,17 +22,9 @@ object ScalatestTestData with CirceJsonStringProvider with KebsJsonSchema with KebsScalacheckGenerators { - val routeRepresentation1: RouteRepresentation[Unit, Unit] = RouteRepresentation( - "description1", - "method1", - "path1" - ) - - val routeRepresentation2: RouteRepresentation[Unit, Unit] = RouteRepresentation( - "description1", - "method1", - "path1" - ) + val routeRepresentation1: RouteRepresentation[Unit, Unit] = RouteRepresentation("description1", "method1", "path1") + + val routeRepresentation2: RouteRepresentation[Unit, Unit] = RouteRepresentation("description1", "method1", "path1") val text11 = "returns Ok test case" val text12 = "returns NotFound test" @@ -69,10 +61,13 @@ class AkkaHttpScalatestFetcherSpec extends Specification { fetcher.fetch(reflections, "pl.iterators.baklava") should containTheSameElementsAs( List( - EnrichedRouteRepresentation(ScalatestTestData.routeRepresentation1, - List(ScalatestTestData.text11, ScalatestTestData.text12).map(t => s"should $t")), - EnrichedRouteRepresentation(ScalatestTestData.routeRepresentation2, List(ScalatestTestData.text21).map(t => s"should $t")), - )) + EnrichedRouteRepresentation( + ScalatestTestData.routeRepresentation1, + List(ScalatestTestData.text11, ScalatestTestData.text12).map(t => s"should $t") + ), + EnrichedRouteRepresentation(ScalatestTestData.routeRepresentation2, List(ScalatestTestData.text21).map(t => s"should $t")) + ) + ) } } diff --git a/specs2/src/main/scala/pl/iterators/baklava/fetcher/Specs2Fetcher.scala b/specs2/src/main/scala/pl/iterators/baklava/fetcher/Specs2Fetcher.scala index 488ef6f..90caeee 100644 --- a/specs2/src/main/scala/pl/iterators/baklava/fetcher/Specs2Fetcher.scala +++ b/specs2/src/main/scala/pl/iterators/baklava/fetcher/Specs2Fetcher.scala @@ -5,7 +5,7 @@ import org.specs2.specification.core.Env import pl.iterators.baklava.core.fetchers.Fetcher import pl.iterators.baklava.core.model.{EnrichedRouteRepresentation, RouteRepresentation} -import scala.collection.JavaConverters.asScalaSetConverter +import scala.jdk.CollectionConverters._ class Specs2Fetcher extends Fetcher { override def fetch(reflections: Reflections, mainPackageName: String): List[EnrichedRouteRepresentation[_, _]] = { diff --git a/specs2/src/test/scala/pl/iterators/baklava/fetcher/AkkaHttpSpecs2FetcherSpec.scala b/specs2/src/test/scala/pl/iterators/baklava/fetcher/AkkaHttpSpecs2FetcherSpec.scala index 6306aec..e389b3b 100644 --- a/specs2/src/test/scala/pl/iterators/baklava/fetcher/AkkaHttpSpecs2FetcherSpec.scala +++ b/specs2/src/test/scala/pl/iterators/baklava/fetcher/AkkaHttpSpecs2FetcherSpec.scala @@ -21,17 +21,9 @@ object Specs2TestData with SprayJsonStringProvider with KebsJsonSchema with KebsScalacheckGenerators { - val routeRepresentation1: RouteRepresentation[Unit, Unit] = RouteRepresentation( - "description1", - "method1", - "path1" - ) - - val routeRepresentation2: RouteRepresentation[Unit, Unit] = RouteRepresentation( - "description1", - "method1", - "path1" - ) + val routeRepresentation1: RouteRepresentation[Unit, Unit] = RouteRepresentation("description1", "method1", "path1") + + val routeRepresentation2: RouteRepresentation[Unit, Unit] = RouteRepresentation("description1", "method1", "path1") val text11 = "returns Ok test case" val text12 = "returns NotFound test" @@ -71,8 +63,9 @@ class AkkaHttpSpecs2FetcherSpec extends Specification { fetcher.fetch(reflections, "pl.iterators.baklava") should containTheSameElementsAs( List( EnrichedRouteRepresentation(Specs2TestData.routeRepresentation1, List("it should", Specs2TestData.text11, Specs2TestData.text12)), - EnrichedRouteRepresentation(Specs2TestData.routeRepresentation2, List(Specs2TestData.text21)), - )) + EnrichedRouteRepresentation(Specs2TestData.routeRepresentation2, List(Specs2TestData.text21)) + ) + ) } } diff --git a/sprayjson/src/main/scala/pl/iterators/baklava/sprayjson/SprayJsonStringProvider.scala b/sprayjson/src/main/scala/pl/iterators/baklava/sprayjson/SprayJsonStringProvider.scala index b7c54ed..b29aa00 100644 --- a/sprayjson/src/main/scala/pl/iterators/baklava/sprayjson/SprayJsonStringProvider.scala +++ b/sprayjson/src/main/scala/pl/iterators/baklava/sprayjson/SprayJsonStringProvider.scala @@ -5,12 +5,10 @@ import spray.json._ trait SprayJsonStringProvider { - implicit val unitPrinter = new JsonStringPrinter[Unit] { + implicit val unitPrinter: JsonStringPrinter[Unit] = new JsonStringPrinter[Unit] { override def printJson(obj: Unit): String = "" } - implicit def sprayJsonString[T](implicit jsonWriter: JsonWriter[T]) = new JsonStringPrinter[T] { - override def printJson(obj: T): String = obj.toJson(jsonWriter).prettyPrint - } + implicit def sprayJsonString[T](implicit jsonWriter: JsonWriter[T]): JsonStringPrinter[T] = (obj: T) => obj.toJson(jsonWriter).prettyPrint }