diff --git a/build.sbt b/build.sbt
index 5182b526..a54575dd 100644
--- a/build.sbt
+++ b/build.sbt
@@ -1,9 +1,12 @@
import sbt.Compile
import sbt.Keys.cleanFiles
-val releaseVersion = sys.env.getOrElse("TAG", "1.0.1-Gamma")
+
+val releaseVersion = sys.env.getOrElse("TAG", "1.1.0-Three.3")
+
addCommandAlias("publishSmithy4Play", "smithy4play/publish")
addCommandAlias("publishLocalSmithy4Play", "smithy4play/publishLocal")
addCommandAlias("generateCoverage", "clean; coverage; test; coverageReport")
+
val token = sys.env.getOrElse("GITHUB_TOKEN", "")
val githubSettings = Seq(
githubOwner := "innFactory",
@@ -21,30 +24,28 @@ val githubSettings = Seq(
)
)
-scalaVersion := "2.13.13"
+scalaVersion := "3.3.1"
-val defaultProjectSettings = Seq(
- scalaVersion := "2.13.13",
+val sharedSettings = Seq(
+ scalaVersion := "3.3.1",
+ scalacOptions ++= Seq("-Ykind-projector:underscores"),
organization := "de.innfactory",
version := releaseVersion
) ++ githubSettings
-val sharedSettings = defaultProjectSettings
lazy val smithy4play = project
.in(file("smithy4play"))
.enablePlugins(Smithy4sCodegenPlugin)
.settings(
sharedSettings,
- addCompilerPlugin("org.typelevel" % "kind-projector" % "0.13.3" cross CrossVersion.full),
+// addCompilerPlugin("org.typelevel" % "kind-projector" % "0.13.3" cross CrossVersion.full),
scalaVersion := Dependencies.scalaVersion,
Compile / smithy4sAllowedNamespaces := List("smithy.smithy4play", "aws.protocols"),
Compile / smithy4sInputDirs := Seq(
(ThisBuild / baseDirectory).value / "smithy4play" / "src" / "resources" / "META_INF" / "smithy"
),
- Compile / smithy4sOutputDir := (ThisBuild / baseDirectory).value / "smithy4play" / "target" / "scala-2.13" / "src_managed" / "main",
+ Compile / smithy4sOutputDir := (Compile / sourceManaged).value / "main",
name := "smithy4play",
- scalacOptions += "-Ymacro-annotations",
- Compile / compile / wartremoverWarnings ++= Warts.unsafe,
libraryDependencies ++= Dependencies.list
)
@@ -55,8 +56,6 @@ lazy val smithy4playTest = project
sharedSettings,
scalaVersion := Dependencies.scalaVersion,
name := "smithy4playTest",
- scalacOptions += "-Ymacro-annotations",
- Compile / compile / wartremoverWarnings ++= Warts.unsafe,
cleanKeepFiles += (ThisBuild / baseDirectory).value / "smithy4playTest" / "app",
cleanFiles += (ThisBuild / baseDirectory).value / "smithy4playTest" / "app" / "specs" / "testDefinitions" / "test",
Compile / smithy4sInputDirs := Seq((ThisBuild / baseDirectory).value / "smithy4playTest" / "testSpecs"),
diff --git a/project/Dependencies.scala b/project/Dependencies.scala
index 34f41550..56c51595 100644
--- a/project/Dependencies.scala
+++ b/project/Dependencies.scala
@@ -3,26 +3,26 @@ import sbt._
object Dependencies {
- val playVersion = "2.9.2"
- val typesafePlay = "com.typesafe.play" %% "play" % playVersion
+ val playVersion = "3.0.1"
+ val typesafePlay = "org.playframework" %% "play" % playVersion
- val scalaVersion = "2.13.13"
- val smithy4sVersion = "0.18.15"
+ val scalaVersion = "3.3.1"
+ val smithy4sVersion = "0.18.23"
val smithyCore = "com.disneystreaming.smithy4s" %% "smithy4s-core" % smithy4sVersion
val smithyJson = "com.disneystreaming.smithy4s" %% "smithy4s-json" % smithy4sVersion
val smithyXml = "com.disneystreaming.smithy4s" %% "smithy4s-xml" % smithy4sVersion
val smithy4sCompliance = "com.disneystreaming.smithy4s" %% "smithy4s-compliance-tests" % smithy4sVersion
- val alloyCore = "com.disneystreaming.alloy" % "alloy-core" % "0.3.6"
- val alloyOpenapi = "com.disneystreaming.alloy" %% "alloy-openapi" % "0.3.6"
+ val alloyCore = "com.disneystreaming.alloy" % "alloy-core" % "0.3.11"
+ val alloyOpenapi = "com.disneystreaming.alloy" %% "alloy-openapi" % "0.3.11"
- val classgraph = "io.github.classgraph" % "classgraph" % "4.8.168"
- val smithyVersion = "1.45.0"
+ val classgraph = "io.github.classgraph" % "classgraph" % "4.8.174"
+ val smithyVersion = "1.50.0"
val testTraits =
"software.amazon.smithy" % "smithy-protocol-test-traits" % smithyVersion
val scalatestPlus =
- "org.scalatestplus.play" %% "scalatestplus-play" % "5.1.0" % Test
- val cats = "org.typelevel" %% "cats-core" % "2.9.0"
+ "org.scalatestplus.play" %% "scalatestplus-play" % "7.0.1" % Test
+ val cats = "org.typelevel" %% "cats-core" % "2.12.0"
lazy val list = Seq(
smithyCore,
diff --git a/project/build.properties b/project/build.properties
index fbf0bfc7..ae537384 100644
--- a/project/build.properties
+++ b/project/build.properties
@@ -1,2 +1,2 @@
sbt.version = 1.9.8
-scala.version = 2.13.2
+scala.version = 3.3.1
diff --git a/project/plugins.sbt b/project/plugins.sbt
index 5ac98de8..2655002e 100644
--- a/project/plugins.sbt
+++ b/project/plugins.sbt
@@ -1,8 +1,7 @@
addSbtPlugin("com.codecommit" %% "sbt-github-packages" % "0.5.3")
-addSbtPlugin("org.wartremover" %% "sbt-wartremover" % "3.1.6")
addSbtPlugin("org.scalameta" %% "sbt-scalafmt" % "2.5.2")
-addSbtPlugin("com.disneystreaming.smithy4s" %% "smithy4s-sbt-codegen" % "0.18.15")
-addSbtPlugin("com.typesafe.play" %% "sbt-plugin" % "2.9.2")
+addSbtPlugin("com.disneystreaming.smithy4s" %% "smithy4s-sbt-codegen" % "0.18.23")
+addSbtPlugin("org.playframework" % "sbt-plugin" % "3.0.1")
addSbtPlugin("org.scoverage" %% "sbt-scoverage" % "2.0.11")
ThisBuild / dependencyOverrides ++= Seq(
diff --git a/smithy4play/src/main/scala/de/innfactory/smithy4play/AutoRoutableController.scala b/smithy4play/src/main/scala/de/innfactory/smithy4play/AutoRoutableController.scala
index 4d8042a5..2a977810 100644
--- a/smithy4play/src/main/scala/de/innfactory/smithy4play/AutoRoutableController.scala
+++ b/smithy4play/src/main/scala/de/innfactory/smithy4play/AutoRoutableController.scala
@@ -4,23 +4,25 @@ import com.github.plokhotnyuk.jsoniter_scala.core.ReaderConfig
import de.innfactory.smithy4play.middleware.MiddlewareBase
import play.api.mvc.ControllerComponents
import play.api.routing.Router.Routes
+import smithy4s.json.JsoniterCodecCompiler
import smithy4s.kinds.FunctorAlgebra
import scala.concurrent.ExecutionContext
trait AutoRoutableController {
+ type Router = (Seq[MiddlewareBase], ReaderConfig, JsoniterCodecCompiler) => Routes
- implicit def transformToRouter[Alg[_[_, _, _, _, _]], F[
- _
- ] <: ContextRoute[_]](
+ implicit def transformToRouter[Alg[_[_, _, _, _, _]], F[_] <: ContextRoute[?]](
impl: FunctorAlgebra[Alg, F]
)(implicit
service: smithy4s.Service[Alg],
ec: ExecutionContext,
cc: ControllerComponents
- ): (Seq[MiddlewareBase], ReaderConfig) => Routes = (middlewares: Seq[MiddlewareBase], readerConfig: ReaderConfig) =>
- new SmithyPlayRouter[Alg, F](impl, service).routes(middlewares, readerConfig)
+ ): Router =
+ (middlewares: Seq[MiddlewareBase], readerConfig: ReaderConfig, jsoniterCodecCompiler: JsoniterCodecCompiler) =>
+ new SmithyPlayRouter[Alg, F](impl, service)
+ .routes(middlewares, readerConfig, jsoniterCodecCompiler)
- val router: (Seq[MiddlewareBase], ReaderConfig) => Routes
+ val router: Router
}
diff --git a/smithy4play/src/main/scala/de/innfactory/smithy4play/AutoRouter.scala b/smithy4play/src/main/scala/de/innfactory/smithy4play/AutoRouter.scala
index 198a7264..44cca6a5 100644
--- a/smithy4play/src/main/scala/de/innfactory/smithy4play/AutoRouter.scala
+++ b/smithy4play/src/main/scala/de/innfactory/smithy4play/AutoRouter.scala
@@ -7,9 +7,9 @@ import io.github.classgraph.{ ClassGraph, ScanResult }
import play.api.Application
import play.api.mvc.ControllerComponents
import play.api.routing.Router.Routes
+import smithy4s.json.Json
-import java.util.Optional
-import javax.inject.{ Inject, Provider, Singleton }
+import javax.inject.{ Inject, Singleton }
import scala.concurrent.ExecutionContext
import scala.jdk.CollectionConverters.CollectionHasAsScala
import scala.util.Try
@@ -23,8 +23,9 @@ class AutoRouter @Inject(
config: Config
) extends BaseRouter {
- private val pkg = config.getString("smithy4play.autoRoutePackage")
- private val readerConfig = ReaderConfig.fromApplicationConfig(config)
+ private val pkg = config.getString("smithy4play.autoRoutePackage")
+ private val readerConfig = ReaderConfig.fromApplicationConfig(config)
+ private val jsoniterCodecCompiler = Json.jsoniter.fromApplicationConfig(config)
override val controllers: Seq[Routes] = {
val classGraphScanner: ScanResult = new ClassGraph().enableAllInfo().acceptPackages(pkg).scan()
@@ -34,14 +35,18 @@ class AutoRouter @Inject(
}.toOption.getOrElse(Seq(validateAuthMiddleware))
logger.debug(s"[AutoRouter] found ${controllers.size().toString} controllers")
logger.debug(s"[AutoRouter] found ${middlewares.size.toString} middlewares")
- val routes = controllers.asScala.map(_.loadClass(true)).map(clazz => createFromClass(clazz, middlewares)).toSeq
+ val routes = controllers.asScala
+ .filter(!_.isAbstract)
+ .map(_.loadClass(true))
+ .map(clazz => createFromClass(clazz, middlewares))
+ .toSeq
classGraphScanner.close()
routes
}
- private def createFromClass(clazz: Class[_], middlewares: Seq[MiddlewareBase]): Routes =
+ private def createFromClass(clazz: Class[?], middlewares: Seq[MiddlewareBase]): Routes =
app.injector.instanceOf(clazz) match {
- case c: AutoRoutableController => c.router(middlewares, readerConfig)
+ case c: AutoRoutableController => c.router(middlewares, readerConfig, jsoniterCodecCompiler)
}
}
diff --git a/smithy4play/src/main/scala/de/innfactory/smithy4play/AutoRoutingMacro.scala b/smithy4play/src/main/scala/de/innfactory/smithy4play/AutoRoutingMacro.scala
deleted file mode 100644
index b27b6c1f..00000000
--- a/smithy4play/src/main/scala/de/innfactory/smithy4play/AutoRoutingMacro.scala
+++ /dev/null
@@ -1,29 +0,0 @@
-package de.innfactory.smithy4play
-
-import scala.reflect.macros.whitebox
-
-object AutoRoutingMacro {
- def impl(c: whitebox.Context)(annottees: c.Tree*): c.Tree = {
- import c.universe._
- annottees match {
- case List(
- q"$mods class $className $ctorMods(...$paramss) extends { ..$earlydefns } with ..$parentss { $self => ..$body }"
- ) =>
- q"""$mods class $className $ctorMods(...$paramss)
- extends { ..$earlydefns }
- with ..$parentss
- with de.innfactory.smithy4play.AutoRoutableController
- { $self =>
- override val router:
- (Seq[de.innfactory.smithy4play.middleware.MiddlewareBase], com.github.plokhotnyuk.jsoniter_scala.core.ReaderConfig)
- => play.api.routing.Router.Routes = this
- ..$body }
- """
- case _ =>
- c.abort(
- c.enclosingPosition,
- "RegisterClass: An AutoRouter Annotation on this type of Class is not supported."
- )
- }
- }
-}
diff --git a/smithy4play/src/main/scala/de/innfactory/smithy4play/BaseRouter.scala b/smithy4play/src/main/scala/de/innfactory/smithy4play/BaseRouter.scala
index e5f6397d..ba887931 100644
--- a/smithy4play/src/main/scala/de/innfactory/smithy4play/BaseRouter.scala
+++ b/smithy4play/src/main/scala/de/innfactory/smithy4play/BaseRouter.scala
@@ -14,7 +14,7 @@ abstract class BaseRouter(implicit
implicit def transformToRouter[Alg[_[_, _, _, _, _]], F[
_
- ] <: ContextRoute[_]](
+ ] <: ContextRoute[?]](
impl: FunctorAlgebra[Alg, F]
)(implicit
serviceProvider: smithy4s.Service[Alg],
diff --git a/smithy4play/src/main/scala/de/innfactory/smithy4play/CodecDecider.scala b/smithy4play/src/main/scala/de/innfactory/smithy4play/CodecDecider.scala
index 3c769e65..3d2b7756 100644
--- a/smithy4play/src/main/scala/de/innfactory/smithy4play/CodecDecider.scala
+++ b/smithy4play/src/main/scala/de/innfactory/smithy4play/CodecDecider.scala
@@ -2,22 +2,23 @@ package de.innfactory.smithy4play
import com.github.plokhotnyuk.jsoniter_scala.core.ReaderConfig
import play.api.http.MimeTypes
-import smithy4s.capability.instances.either._
+import smithy4s.capability.instances.either.*
import smithy4s.codecs.Writer.CachedCompiler
-import smithy4s.codecs._
+import smithy4s.codecs.*
import smithy4s.http.{ HttpResponse, HttpRestSchema, Metadata, MetadataError }
-import smithy4s.json.Json
+import smithy4s.json.{ Json, JsoniterCodecCompiler }
import smithy4s.kinds.PolyFunction
import smithy4s.schema.CachedSchemaCompiler
import smithy4s.xml.Xml
import smithy4s.{ codecs, Blob }
-case class CodecDecider(readerConfig: ReaderConfig) {
+case class CodecDecider(
+ readerConfig: ReaderConfig,
+ jsoniterCodecCompiler: JsoniterCodecCompiler
+) {
private val jsonCodecs = Json.payloadCodecs
- .withJsoniterCodecCompiler(
- Json.jsoniter
- )
+ .withJsoniterCodecCompiler(jsoniterCodecCompiler)
.withJsoniterReaderConfig(readerConfig)
private val jsonEncoder: BlobEncoder.Compiler = jsonCodecs.encoders
@@ -28,7 +29,7 @@ case class CodecDecider(readerConfig: ReaderConfig) {
def encoder(
contentType: Seq[String]
): CachedSchemaCompiler[codecs.BlobEncoder] =
- contentType match {
+ contentType.map(_.split(";").head) match {
case Seq(MimeTypes.JSON) => jsonEncoder
case Seq(MimeTypes.XML) => Xml.encoders
case _ =>
@@ -38,18 +39,18 @@ case class CodecDecider(readerConfig: ReaderConfig) {
def requestDecoder(
contentType: Seq[String]
- ): CachedSchemaCompiler[Decoder[Either[Throwable, *], PlayHttpRequest[Blob], *]] =
- HttpRestSchema.combineDecoderCompilers[Either[Throwable, *], PlayHttpRequest[Blob]](
+ ): CachedSchemaCompiler[Decoder[Either[Throwable, _], PlayHttpRequest[Blob], _]] =
+ HttpRestSchema.combineDecoderCompilers[Either[Throwable, _], PlayHttpRequest[Blob]](
metadataDecoder
.mapK(
- Decoder.in[Either[MetadataError, *]].composeK[Metadata, PlayHttpRequest[Blob]](_.metadata)
+ Decoder.in[Either[MetadataError, _]].composeK[Metadata, PlayHttpRequest[Blob]](_.metadata)
)
- .asInstanceOf[CachedSchemaCompiler[Decoder[Either[Throwable, *], PlayHttpRequest[Blob], *]]],
+ .asInstanceOf[CachedSchemaCompiler[Decoder[Either[Throwable, _], PlayHttpRequest[Blob], _]]],
decoder(contentType)
.mapK(
- Decoder.in[Either[PayloadError, *]].composeK[Blob, PlayHttpRequest[Blob]](_.body)
+ Decoder.in[Either[PayloadError, _]].composeK[Blob, PlayHttpRequest[Blob]](_.body)
)
- .asInstanceOf[CachedSchemaCompiler[Decoder[Either[Throwable, *], PlayHttpRequest[Blob], *]]],
+ .asInstanceOf[CachedSchemaCompiler[Decoder[Either[Throwable, _], PlayHttpRequest[Blob], _]]],
_ => Right(())
)(eitherZipper)
@@ -68,22 +69,22 @@ case class CodecDecider(readerConfig: ReaderConfig) {
def httpResponseDecoder(
contentType: Seq[String]
- ): CachedSchemaCompiler[Decoder[Either[Throwable, *], HttpResponse[Blob], *]] =
- HttpRestSchema.combineDecoderCompilers[Either[Throwable, *], HttpResponse[Blob]](
+ ): CachedSchemaCompiler[Decoder[Either[Throwable, _], HttpResponse[Blob], _]] =
+ HttpRestSchema.combineDecoderCompilers[Either[Throwable, _], HttpResponse[Blob]](
metadataDecoder
.mapK(
Decoder
- .in[Either[MetadataError, *]]
+ .in[Either[MetadataError, _]]
.composeK[Metadata, HttpResponse[Blob]](r =>
Metadata(Map.empty, Map.empty, headers = r.headers, statusCode = Some(r.statusCode))
)
)
- .asInstanceOf[CachedSchemaCompiler[Decoder[Either[Throwable, *], HttpResponse[Blob], *]]],
+ .asInstanceOf[CachedSchemaCompiler[Decoder[Either[Throwable, _], HttpResponse[Blob], _]]],
decoder(contentType)
.mapK(
- Decoder.in[Either[PayloadError, *]].composeK[Blob, HttpResponse[Blob]](_.body)
+ Decoder.in[Either[PayloadError, _]].composeK[Blob, HttpResponse[Blob]](_.body)
)
- .asInstanceOf[CachedSchemaCompiler[Decoder[Either[Throwable, *], HttpResponse[Blob], *]]],
+ .asInstanceOf[CachedSchemaCompiler[Decoder[Either[Throwable, _], HttpResponse[Blob], _]]],
_ => Right(())
)(eitherZipper)
@@ -108,9 +109,9 @@ case class CodecDecider(readerConfig: ReaderConfig) {
(insensitive, value)
})
)
- private val httpRequestBlobPipe: PolyFunction[Encoder[Blob, *], Writer[HttpResponse[Blob], *]] =
+ private val httpRequestBlobPipe: PolyFunction[Encoder[Blob, _], Writer[HttpResponse[Blob], _]] =
smithy4s.codecs.Encoder.pipeToWriterK[HttpResponse[Blob], Blob](httpRequestBodyLift)
- private val httpRequestMetadataPipe: PolyFunction[Encoder[Metadata, *], Writer[HttpResponse[Blob], *]] =
+ private val httpRequestMetadataPipe: PolyFunction[Encoder[Metadata, _], Writer[HttpResponse[Blob], _]] =
smithy4s.codecs.Encoder.pipeToWriterK(httpRequestMetadataLift)
private val blobLift: Writer[EndpointRequest, Blob] =
@@ -121,15 +122,15 @@ case class CodecDecider(readerConfig: ReaderConfig) {
(insensitive, value)
})
)
- private val blobPipe: PolyFunction[Encoder[Blob, *], Writer[EndpointRequest, *]] =
+ private val blobPipe: PolyFunction[Encoder[Blob, _], Writer[EndpointRequest, _]] =
smithy4s.codecs.Encoder.pipeToWriterK[EndpointRequest, Blob](blobLift)
- private val metadataPipe: PolyFunction[Encoder[Metadata, *], Writer[EndpointRequest, *]] =
+ private val metadataPipe: PolyFunction[Encoder[Metadata, _], Writer[EndpointRequest, _]] =
smithy4s.codecs.Encoder.pipeToWriterK(metadataLift)
def decoder(
contentType: Seq[String]
): CachedSchemaCompiler[BlobDecoder] =
- contentType match {
+ contentType.map(_.split(";").head) match {
case Seq(MimeTypes.JSON) => jsonDecoder
case Seq(MimeTypes.XML) => Xml.decoders
case _ =>
diff --git a/smithy4play/src/main/scala/de/innfactory/smithy4play/RoutingContext.scala b/smithy4play/src/main/scala/de/innfactory/smithy4play/RoutingContext.scala
index 88eaee32..46f7b916 100644
--- a/smithy4play/src/main/scala/de/innfactory/smithy4play/RoutingContext.scala
+++ b/smithy4play/src/main/scala/de/innfactory/smithy4play/RoutingContext.scala
@@ -10,9 +10,9 @@ case class RoutingContext(
attributes: Map[String, Any],
requestHeader: RequestHeader
) {
- def hasHints(s: ShapeTag.Companion[_]): Boolean = hasEndpointHints(s) || hasServiceHints(s)
- def hasServiceHints(s: ShapeTag.Companion[_]): Boolean = serviceHints.has(s.tagInstance)
- def hasEndpointHints(s: ShapeTag.Companion[_]): Boolean = endpointHints.has(s.tagInstance)
+ def hasHints(s: ShapeTag.Companion[?]): Boolean = hasEndpointHints(s) || hasServiceHints(s)
+ def hasServiceHints(s: ShapeTag.Companion[?]): Boolean = serviceHints.has(s.tagInstance)
+ def hasEndpointHints(s: ShapeTag.Companion[?]): Boolean = endpointHints.has(s.tagInstance)
}
object RoutingContext {
diff --git a/smithy4play/src/main/scala/de/innfactory/smithy4play/SmithyPlayEndpoint.scala b/smithy4play/src/main/scala/de/innfactory/smithy4play/SmithyPlayEndpoint.scala
index 64b682f5..7cccc110 100644
--- a/smithy4play/src/main/scala/de/innfactory/smithy4play/SmithyPlayEndpoint.scala
+++ b/smithy4play/src/main/scala/de/innfactory/smithy4play/SmithyPlayEndpoint.scala
@@ -3,6 +3,7 @@ package de.innfactory.smithy4play
import cats.data.{ EitherT, Kleisli }
import de.innfactory.smithy4play
import de.innfactory.smithy4play.middleware.MiddlewareBase
+import org.apache.pekko.util.ByteString
import play.api.mvc._
import smithy4s.codecs.PayloadError
import smithy4s.http._
@@ -13,7 +14,7 @@ import smithy4s.{ Blob, Endpoint, Service }
import javax.inject.Inject
import scala.concurrent.{ ExecutionContext, Future }
-class SmithyPlayEndpoint[Alg[_[_, _, _, _, _]], F[_] <: ContextRoute[_], Op[_, _, _, _, _], I, E, O, SI, SO](
+class SmithyPlayEndpoint[Alg[_[_, _, _, _, _]], F[_] <: ContextRoute[?], Op[_, _, _, _, _], I, E, O, SI, SO](
service: Service[Alg],
impl: FunctorInterpreter[Op, F],
middleware: Seq[MiddlewareBase],
@@ -27,10 +28,11 @@ class SmithyPlayEndpoint[Alg[_[_, _, _, _, _]], F[_] <: ContextRoute[_], Op[_, _
private val endpointHints = endpoint.hints
private val serviceContentType: String = serviceHints.toMimeType
- private implicit val inputSchema: Schema[I] = endpoint.input
- private implicit val outputSchema: Schema[O] = endpoint.output
-
- def handler(v1: RequestHeader): Handler =
+ private implicit val inputSchema: Schema[I] = endpoint.input
+ private implicit val outputSchema: Schema[O] = endpoint.output
+ private val outputMetadataEncoder: Metadata.Encoder[O] =
+ Metadata.Encoder.fromSchema(outputSchema)
+ def handler(v1: RequestHeader): Handler =
httpEndpoint.map { httpEp =>
Action.async(parse.raw) { implicit request =>
if (request.body.size > 0 && request.body.asBytes().isEmpty) {
@@ -63,9 +65,13 @@ class SmithyPlayEndpoint[Alg[_[_, _, _, _, _]], F[_] <: ContextRoute[_], Op[_, _
private def mapToEndpointResult(
statusCode: Int
- )(output: O)(implicit defaultContentType: ContentType): HttpResponse[Blob] =
+ )(output: O)(implicit defaultContentType: ContentType): HttpResponse[Blob] = {
+ val outputContentType = outputMetadataEncoder.encode(output).headers.get(CaseInsensitive("content-type")) match {
+ case Some(value) => value
+ case None => Seq(defaultContentType.value)
+ }
codecDecider
- .httpMessageEncoder(Seq(defaultContentType.value))
+ .httpMessageEncoder(outputContentType)
.fromSchema(outputSchema)
.write(
HttpResponse(
@@ -75,6 +81,7 @@ class SmithyPlayEndpoint[Alg[_[_, _, _, _, _]], F[_] <: ContextRoute[_], Op[_, _
),
output
)
+ }
private def getPathParams(
v1: RequestHeader,
diff --git a/smithy4play/src/main/scala/de/innfactory/smithy4play/SmithyPlayRouter.scala b/smithy4play/src/main/scala/de/innfactory/smithy4play/SmithyPlayRouter.scala
index 268c8432..af9e15d2 100644
--- a/smithy4play/src/main/scala/de/innfactory/smithy4play/SmithyPlayRouter.scala
+++ b/smithy4play/src/main/scala/de/innfactory/smithy4play/SmithyPlayRouter.scala
@@ -8,28 +8,30 @@ import play.api.mvc.{ AbstractController, ControllerComponents, Handler, Request
import play.api.routing.Router.Routes
import smithy4s.codecs.{ BlobEncoder, PayloadDecoder, PayloadEncoder }
import smithy4s.http.{ HttpEndpoint, PathSegment }
-import smithy4s.json.{ Json, JsonPayloadCodecCompiler }
+import smithy4s.json.{ Json, JsonPayloadCodecCompiler, JsoniterCodecCompiler }
import smithy4s.kinds.{ FunctorAlgebra, Kind1, PolyFunction5 }
import smithy4s.schema.CachedSchemaCompiler
import smithy4s.xml.Xml
import scala.concurrent.ExecutionContext
-class SmithyPlayRouter[Alg[_[_, _, _, _, _]], F[
- _
-] <: ContextRoute[_]](
+class SmithyPlayRouter[Alg[_[_, _, _, _, _]], F[_] <: ContextRoute[?]](
impl: FunctorAlgebra[Alg, F],
service: smithy4s.Service[Alg]
)(implicit cc: ControllerComponents, ec: ExecutionContext)
extends AbstractController(cc) {
- def routes(middlewares: Seq[MiddlewareBase], readerConfig: ReaderConfig): Routes = {
+ def routes(
+ middlewares: Seq[MiddlewareBase],
+ readerConfig: ReaderConfig,
+ jsoniterCodecCompiler: JsoniterCodecCompiler
+ ): Routes = {
val interpreter: PolyFunction5[service.Operation, Kind1[F]#toKind5] = service.toPolyFunction[Kind1[F]#toKind5](impl)
- val endpoints: Seq[service.Endpoint[_, _, _, _, _]] = service.endpoints
- val httpEndpoints: Seq[Either[HttpEndpoint.HttpEndpointError, HttpEndpoint[_]]] =
+ val endpoints: Seq[service.Endpoint[?, ?, ?, ?, ?]] = service.endpoints
+ val httpEndpoints: Seq[Either[HttpEndpoint.HttpEndpointError, HttpEndpoint[?]]] =
endpoints.map(ep => HttpEndpoint.cast(ep.schema))
- val codecDecider = CodecDecider(readerConfig)
+ val codecDecider = CodecDecider(readerConfig, jsoniterCodecCompiler)
new PartialFunction[RequestHeader, Handler] {
override def isDefinedAt(x: RequestHeader): Boolean = {
@@ -64,7 +66,7 @@ class SmithyPlayRouter[Alg[_[_, _, _, _, _]], F[
private def checkIfRequestHeaderMatchesEndpoint(
x: RequestHeader,
- ep: HttpEndpoint[_]
+ ep: HttpEndpoint[?]
): Boolean = {
ep.path.map {
case PathSegment.StaticSegment(value) => value
diff --git a/smithy4play/src/main/scala/de/innfactory/smithy4play/client/GenericAPIClient.scala b/smithy4play/src/main/scala/de/innfactory/smithy4play/client/GenericAPIClient.scala
index 29ff88e0..46f84738 100644
--- a/smithy4play/src/main/scala/de/innfactory/smithy4play/client/GenericAPIClient.scala
+++ b/smithy4play/src/main/scala/de/innfactory/smithy4play/client/GenericAPIClient.scala
@@ -4,6 +4,7 @@ import cats.data.Kleisli
import com.github.plokhotnyuk.jsoniter_scala.core.ReaderConfig
import de.innfactory.smithy4play.{ ClientResponse, CodecDecider, RunnableClientRequest }
import smithy4s.Service
+import smithy4s.json.{ Json, JsoniterCodecCompiler }
import smithy4s.kinds.{ Kind1, PolyFunction5 }
import scala.concurrent.ExecutionContext
@@ -12,11 +13,18 @@ private class GenericAPIClient[Alg[_[_, _, _, _, _]]](
service: Service[Alg],
client: RequestClient,
readerConfig: ReaderConfig,
+ jsoniterCodecCompiler: JsoniterCodecCompiler,
additionalSuccessCodes: List[Int] = List.empty
)(implicit ec: ExecutionContext) {
private val smithyPlayClient =
- new SmithyPlayClient("/", service, client, CodecDecider(readerConfig), additionalSuccessCodes)
+ new SmithyPlayClient(
+ "/",
+ service,
+ client,
+ CodecDecider(readerConfig, jsoniterCodecCompiler),
+ additionalSuccessCodes
+ )
/* Takes a service and creates a Transformation[Op, ClientRequest] */
private def transformer(): Alg[Kind1[RunnableClientRequest]#toKind5] =
@@ -57,16 +65,18 @@ object GenericAPIClient {
client: RequestClient,
additionalHeaders: Option[Map[String, Seq[String]]],
additionalSuccessCodes: List[Int] = List.empty,
- readerConfig: ReaderConfig = ReaderConfig
+ readerConfig: ReaderConfig = ReaderConfig,
+ jsoniterCodecCompiler: JsoniterCodecCompiler = Json.jsoniter
)(implicit ec: ExecutionContext): Alg[Kind1[ClientResponse]#toKind5] =
- apply(service, additionalHeaders, additionalSuccessCodes, client, readerConfig)
+ apply(service, additionalHeaders, additionalSuccessCodes, client, readerConfig, jsoniterCodecCompiler)
def withClient(
client: RequestClient,
additionalSuccessCodes: List[Int] = List.empty,
- readerConfig: ReaderConfig = ReaderConfig
+ readerConfig: ReaderConfig = ReaderConfig,
+ jsoniterCodecCompiler: JsoniterCodecCompiler = Json.jsoniter
)(implicit ec: ExecutionContext): Alg[Kind1[RunnableClientRequest]#toKind5] =
- apply(service, client, additionalSuccessCodes, readerConfig)
+ apply(service, client, additionalSuccessCodes, readerConfig, jsoniterCodecCompiler)
}
@@ -74,17 +84,21 @@ object GenericAPIClient {
serviceI: Service[Alg],
client: RequestClient,
additionalSuccessCodes: List[Int],
- readerConfig: ReaderConfig
+ readerConfig: ReaderConfig,
+ jsoniterCodecCompiler: JsoniterCodecCompiler
)(implicit ec: ExecutionContext): Alg[Kind1[RunnableClientRequest]#toKind5] =
- new GenericAPIClient(serviceI, client, readerConfig, additionalSuccessCodes).transformer()
+ new GenericAPIClient(serviceI, client, readerConfig, jsoniterCodecCompiler, additionalSuccessCodes).transformer()
def apply[Alg[_[_, _, _, _, _]]](
serviceI: Service[Alg],
additionalHeaders: Option[Map[String, Seq[String]]],
additionalSuccessCodes: List[Int],
client: RequestClient,
- readerConfig: ReaderConfig
+ readerConfig: ReaderConfig,
+ jsoniterCodecCompiler: JsoniterCodecCompiler
)(implicit ec: ExecutionContext): Alg[Kind1[ClientResponse]#toKind5] =
- new GenericAPIClient(serviceI, client, readerConfig, additionalSuccessCodes).transformer(additionalHeaders)
+ new GenericAPIClient(serviceI, client, readerConfig, jsoniterCodecCompiler, additionalSuccessCodes).transformer(
+ additionalHeaders
+ )
}
diff --git a/smithy4play/src/main/scala/de/innfactory/smithy4play/client/SmithyPlayClientEndpoint.scala b/smithy4play/src/main/scala/de/innfactory/smithy4play/client/SmithyPlayClientEndpoint.scala
index 74c1d947..0f96e64f 100644
--- a/smithy4play/src/main/scala/de/innfactory/smithy4play/client/SmithyPlayClientEndpoint.scala
+++ b/smithy4play/src/main/scala/de/innfactory/smithy4play/client/SmithyPlayClientEndpoint.scala
@@ -81,7 +81,7 @@ private[smithy4play] class SmithyPlayClientEndpoint[Op[_, _, _, _, _], I, E, O,
.map(o => HttpResponse(response.statusCode, headers, o))
.leftMap {
case error: PayloadError =>
- SmithyPlayClientEndpointErrorResponse(error.expected.getBytes(), response.statusCode)
+ SmithyPlayClientEndpointErrorResponse(error.toString().getBytes(), response.statusCode)
case error: MetadataError =>
SmithyPlayClientEndpointErrorResponse(error.getMessage().getBytes(), response.statusCode)
}
diff --git a/smithy4play/src/main/scala/de/innfactory/smithy4play/package.scala b/smithy4play/src/main/scala/de/innfactory/smithy4play/package.scala
index c20831b5..5514e356 100644
--- a/smithy4play/src/main/scala/de/innfactory/smithy4play/package.scala
+++ b/smithy4play/src/main/scala/de/innfactory/smithy4play/package.scala
@@ -11,10 +11,10 @@ import play.api.Logger
import play.api.http.MimeTypes
import play.api.libs.json.{ JsValue, Json, OFormat }
import play.api.mvc.{ Headers, RequestHeader }
-import smithy4s.{ Blob, Hints }
import smithy4s.http.{ CaseInsensitive, HttpEndpoint, HttpResponse, Metadata }
+import smithy4s.{ Blob, Hints }
+import smithy4s.json.JsoniterCodecCompiler
-import scala.annotation.{ compileTimeOnly, StaticAnnotation }
import scala.concurrent.Future
import scala.language.experimental.macros
import scala.util.Try
@@ -104,6 +104,17 @@ package object smithy4play {
}
}
+ implicit class EnhancedJsoniterCodecCompiler(codec: JsoniterCodecCompiler) {
+
+ def fromApplicationConfig(config: Config): JsoniterCodecCompiler = {
+ val maxArity =
+ Try(config.getInt("smithy4play.jsoniterCodecCompiler.maxArity")).toOption
+
+ codec
+ .withMaxArity(maxArity.getOrElse(JsoniterCodecCompiler.defaultMaxArity))
+ }
+ }
+
implicit class EnhancedThrowable(throwable: Throwable) {
private val regex1: Regex = """(?s), offset: (?:0x)?[0-9a-fA-F]+, buf:.*""".r
private val regex2: Regex = """(.*), offset: .*, buf:.* (\(path:.*\))""".r
@@ -133,7 +144,7 @@ package object smithy4play {
}
object Smithy4PlayError {
- implicit val format = Json.format[Smithy4PlayError]
+ implicit val format: OFormat[Smithy4PlayError] = Json.format[Smithy4PlayError]
}
private[smithy4play] val logger: slf4j.Logger = Logger("smithy4play").logger
@@ -145,17 +156,10 @@ package object smithy4play {
private[smithy4play] def matchRequestPath(
x: RequestHeader,
- ep: HttpEndpoint[_]
+ ep: HttpEndpoint[?]
): Option[Map[String, String]] =
ep.matches(x.path.replaceFirst("/", "").split("/").filter(_.nonEmpty))
- @compileTimeOnly(
- "Macro failed to expand. \"Add: scalacOptions += \"-Ymacro-annotations\"\" to project settings"
- )
- class AutoRouting extends StaticAnnotation {
- def macroTransform(annottees: Any*): Any = macro AutoRoutingMacro.impl
- }
-
private[smithy4play] trait Showable {
this: Product =>
override def toString: String = this.show
diff --git a/smithy4playTest/app/Module.scala b/smithy4playTest/app/Module.scala
index 0c5297a7..79550275 100755
--- a/smithy4playTest/app/Module.scala
+++ b/smithy4playTest/app/Module.scala
@@ -1,13 +1,13 @@
import com.google.inject.AbstractModule
import controller.middlewares.MiddlewareRegistry
import de.innfactory.smithy4play.middleware.MiddlewareRegistryBase
-import play.api.libs.concurrent.AkkaGuiceSupport
+import play.api.libs.concurrent.PekkoGuiceSupport
/** This module handles the bindings for the API to the Slick implementation.
*
* https://www.playframework.com/documentation/latest/ScalaDependencyInjection#Programmatic-bindings
*/
-class Module extends AbstractModule with AkkaGuiceSupport {
+class Module extends AbstractModule with PekkoGuiceSupport {
override def configure(): Unit =
bind(classOf[MiddlewareRegistryBase]).to(classOf[MiddlewareRegistry])
diff --git a/smithy4playTest/app/controller/TestController.scala b/smithy4playTest/app/controller/TestController.scala
index 20ec6951..6ec10dd2 100644
--- a/smithy4playTest/app/controller/TestController.scala
+++ b/smithy4playTest/app/controller/TestController.scala
@@ -1,21 +1,25 @@
package controller
import cats.data.{ EitherT, Kleisli }
+import com.github.plokhotnyuk.jsoniter_scala.core.ReaderConfig
import controller.models.TestError
-import de.innfactory.smithy4play.{ AutoRouting, ContextRoute, ContextRouteError }
+import de.innfactory.smithy4play.middleware.MiddlewareBase
+import de.innfactory.smithy4play.{ AutoRoutableController, ContextRoute, ContextRouteError }
import play.api.mvc.ControllerComponents
+import play.api.routing.Router.Routes
import smithy4s.Blob
-import testDefinitions.test._
+import testDefinitions.test.*
import javax.inject.{ Inject, Singleton }
import scala.concurrent.{ ExecutionContext, Future }
@Singleton
-@AutoRouting
class TestController @Inject() (implicit
cc: ControllerComponents,
executionContext: ExecutionContext
-) extends TestControllerService[ContextRoute] {
+) extends TestControllerService[ContextRoute]
+ with AutoRoutableController {
+ override val router: Router = this
override def test(): ContextRoute[SimpleTestResponse] = Kleisli { rc =>
rc.attributes.get("Not") match {
@@ -67,4 +71,8 @@ class TestController @Inject() (implicit
override def testWithOtherStatusCode(): ContextRoute[Unit] = Kleisli { rc =>
EitherT.rightT[Future, ContextRouteError](())
}
+
+ override def testWithJsonInputAndBlobOutput(body: JsonInput): ContextRoute[BlobResponse] = Kleisli { rc =>
+ EitherT.rightT[Future, ContextRouteError](BlobResponse(Blob(body.message), "image/png"))
+ }
}
diff --git a/smithy4playTest/app/controller/XmlController.scala b/smithy4playTest/app/controller/XmlController.scala
index 964ec18e..c4461a20 100644
--- a/smithy4playTest/app/controller/XmlController.scala
+++ b/smithy4playTest/app/controller/XmlController.scala
@@ -2,32 +2,39 @@ package controller
import cats.data.{ EitherT, Kleisli }
import cats.implicits.catsSyntaxEitherId
-import de.innfactory.smithy4play.{ AutoRouting, ContextRoute, ContextRouteError }
+import com.github.plokhotnyuk.jsoniter_scala.core.ReaderConfig
+import de.innfactory.smithy4play.middleware.MiddlewareBase
+import de.innfactory.smithy4play.{ AutoRoutableController, ContextRoute, ContextRouteError }
import play.api.mvc.ControllerComponents
+import play.api.routing.Router.Routes
import testDefinitions.test.{ XmlControllerDef, XmlTestInputBody, XmlTestOutput, XmlTestWithInputAndOutputOutput }
import javax.inject.{ Inject, Singleton }
import scala.concurrent.{ ExecutionContext, Future }
@Singleton
-@AutoRouting
class XmlController @Inject() (implicit
cc: ControllerComponents,
executionContext: ExecutionContext
-) extends XmlControllerDef[ContextRoute] {
+) extends XmlControllerDef[ContextRoute]
+ with AutoRoutableController {
+ override val router: Router = this
override def xmlTestWithInputAndOutput(
xmlTest: String,
- body: XmlTestInputBody
+ body: XmlTestInputBody,
+ contentType: Option[String]
): ContextRoute[XmlTestWithInputAndOutputOutput] =
Kleisli { _ =>
EitherT(
Future(
XmlTestWithInputAndOutputOutput(
- XmlTestOutput(body.serverzeit, body.requiredTest + xmlTest, body.requiredInt.map(i => i * i))
+ XmlTestOutput(body.serverzeit, body.requiredTest + xmlTest, body.requiredInt.map(i => i * i)),
+ contentType
)
.asRight[ContextRouteError]
)
)
}
+
}
diff --git a/smithy4playTest/test/TestControllerTest.scala b/smithy4playTest/test/TestControllerTest.scala
index 7bdb8c9b..f03ea09c 100644
--- a/smithy4playTest/test/TestControllerTest.scala
+++ b/smithy4playTest/test/TestControllerTest.scala
@@ -11,9 +11,10 @@ import play.api.libs.json.{ Json, OWrites }
import play.api.mvc.Result
import play.api.test.FakeRequest
import play.api.test.Helpers._
-import smithy4s.Blob
+import smithy4s.{ Blob, Document }
import smithy4s.http.CaseInsensitive
import testDefinitions.test.{
+ JsonInput,
SimpleTestResponse,
TestControllerServiceGen,
TestRequestBody,
@@ -167,6 +168,14 @@ class TestControllerTest extends TestBase {
pngAsBytes mustBe result.body.body
}
+ "route with json body to Blob Endpoint" in {
+ val testString = "StringToBeParsedCorrectly"
+ val result = genericClient.testWithJsonInputAndBlobOutput(JsonInput(testString)).awaitRight(global, 5.hours)
+
+ result.statusCode mustBe 200
+ testString mustBe result.body.body.toUTF8String
+ }
+
"route to Auth Test" in {
val result = genericClient.testAuth().awaitLeft
diff --git a/smithy4playTest/test/XmlControllerTest.scala b/smithy4playTest/test/XmlControllerTest.scala
index d023a5a6..215a00fc 100644
--- a/smithy4playTest/test/XmlControllerTest.scala
+++ b/smithy4playTest/test/XmlControllerTest.scala
@@ -4,11 +4,11 @@ import models.NodeImplicits.NodeEnhancer
import models.TestBase
import play.api.Application
import play.api.inject.guice.GuiceApplicationBuilder
-import play.api.libs.json.{Json, OFormat}
+import play.api.libs.json.{ Json, OFormat }
import play.api.test.FakeRequest
import play.api.test.Helpers._
import smithy4s.http.CaseInsensitive
-import testDefinitions.test.{XmlControllerDefGen, XmlTestInputBody, XmlTestOutput}
+import testDefinitions.test.{ XmlControllerDefGen, XmlTestInputBody, XmlTestOutput }
import scala.concurrent.ExecutionContext.Implicits.global
@@ -33,6 +33,53 @@ class XmlControllerTest extends TestBase {
res.body.body.requiredTestStringConcat mustBe "ThisGetsConcat"
}
+ "route to xml with charset in header endpoint with smithy client" in {
+ val res = genericClient
+ .xmlTestWithInputAndOutput(
+ "Concat",
+ XmlTestInputBody("05.02.2024", "ThisGets", Some(10)),
+ Some("application/xml; charset=utf-8")
+ )
+ .awaitRight
+
+ res.body.body.requiredIntSquared mustBe Some(100)
+ res.body.body.requiredTestStringConcat mustBe "ThisGetsConcat"
+ res.headers.get(CaseInsensitive("content-type")) mustBe Some(List("application/xml; charset=utf-8"))
+ }
+
+ "route to xml with charset in header with external client" in {
+ val concatVal1 = "ConcatThis"
+ val concatVal2 = "Test2"
+ val squareTest = 3
+ val xml =
+
+ {concatVal1}
+ {squareTest}
+
+ val request = route(
+ app,
+ FakeRequest("POST", s"/xml/$concatVal2")
+ .withHeaders(("content-type", "application/xml; charset=utf-8"))
+ .withXmlBody(
+ xml
+ )
+ ).get
+ status(request) mustBe 200
+
+ val result = scala.xml.XML.loadString(contentAsString(request))
+ val resContentType = contentType(request)
+ val resCharset = charset(request)
+
+
+ result.normalize mustBe
+
+ {concatVal1 + concatVal2}
+
+ {squareTest * squareTest}
+ .normalize
+ resContentType.map(_ + "; charset=" + resCharset.getOrElse("")) mustBe Some("application/xml; charset=utf-8")
+ }
+
"route to xml test endpoint with external client" in {
val concatVal1 = "ConcatThis"
val concatVal2 = "Test2"
@@ -115,13 +162,13 @@ class XmlControllerTest extends TestBase {
}
"route to test endpoint with external client and json protocol" in {
- implicit val formatI: OFormat[XmlTestInputBody] = Json.format[XmlTestInputBody]
- implicit val formatO: OFormat[XmlTestOutput] = Json.format[XmlTestOutput]
- val concatVal2 = "Test2"
- val concatVal1 = "ConcatThis"
- val squareTest = Some(15)
- val date = "05.02.2024"
- val request = route(
+ implicit val formatI: OFormat[XmlTestInputBody] = Json.format[XmlTestInputBody]
+ implicit val formatO: OFormat[XmlTestOutput] = Json.format[XmlTestOutput]
+ val concatVal2 = "Test2"
+ val concatVal1 = "ConcatThis"
+ val squareTest = Some(15)
+ val date = "05.02.2024"
+ val request = route(
app,
FakeRequest("POST", s"/xml/$concatVal2")
.withHeaders(("content-type", "application/json"))
@@ -130,7 +177,7 @@ class XmlControllerTest extends TestBase {
)
).get
status(request) mustBe 200
- val result = contentAsJson(request).as[XmlTestOutput]
+ val result = contentAsJson(request).as[XmlTestOutput]
result.requiredTestStringConcat mustBe concatVal1 + concatVal2
result.requiredIntSquared mustBe squareTest.map(s => s * s)
result.serverzeit mustBe date
diff --git a/smithy4playTest/test/models/TestBase.scala b/smithy4playTest/test/models/TestBase.scala
index f173b0d3..671aedeb 100644
--- a/smithy4playTest/test/models/TestBase.scala
+++ b/smithy4playTest/test/models/TestBase.scala
@@ -2,27 +2,26 @@ package models
import de.innfactory.smithy4play.EndpointRequest
import de.innfactory.smithy4play.client.RequestClient
-import org.scalatestplus.play.{BaseOneAppPerSuite, FakeApplicationFactory, PlaySpec}
+import org.scalatestplus.play.{ BaseOneAppPerSuite, FakeApplicationFactory, PlaySpec }
import play.api.mvc.AnyContentAsEmpty
import play.api.test.FakeRequest
-import play.api.test.Helpers.{route, writeableOf_AnyContentAsEmpty}
+import play.api.test.Helpers.{ route, writeableOf_AnyContentAsEmpty }
import smithy4s.Blob
-import smithy4s.http.{CaseInsensitive, HttpResponse}
+import smithy4s.http.{ CaseInsensitive, HttpResponse }
import scala.concurrent.Future
import scala.concurrent.ExecutionContext.Implicits.global
import play.api.Play.materializer
-
trait TestBase extends PlaySpec with BaseOneAppPerSuite with FakeApplicationFactory {
implicit object FakeRequestClient extends RequestClient {
override def send(
- method: String,
- path: String,
- headers: Map[String, Seq[String]],
- result: EndpointRequest
- ): Future[HttpResponse[Blob]] = {
+ method: String,
+ path: String,
+ headers: Map[String, Seq[String]],
+ result: EndpointRequest
+ ): Future[HttpResponse[Blob]] = {
val baseRequest: FakeRequest[AnyContentAsEmpty.type] = FakeRequest(method, path)
.withHeaders(headers.toList.flatMap(headers => headers._2.map(v => (headers._1, v))): _*)
val res =
diff --git a/smithy4playTest/test/models/TestJson.scala b/smithy4playTest/test/models/TestJson.scala
index 094b46bd..9c22a7de 100644
--- a/smithy4playTest/test/models/TestJson.scala
+++ b/smithy4playTest/test/models/TestJson.scala
@@ -1,9 +1,10 @@
package models
-import play.api.libs.json.Json
+import play.api.libs.json.{Json, Reads, Writes}
case class TestJson(message: Option[String])
object TestJson {
- implicit val format = Json.format[TestJson]
+ given Writes[TestJson] = Json.format[TestJson]
+ given Reads[TestJson] = Json.reads[TestJson]
}
diff --git a/smithy4playTest/testSpecs/TestController.smithy b/smithy4playTest/testSpecs/TestController.smithy
index 066ffd2c..2de835da 100644
--- a/smithy4playTest/testSpecs/TestController.smithy
+++ b/smithy4playTest/testSpecs/TestController.smithy
@@ -14,6 +14,7 @@ service TestControllerService {
Health
TestWithBlob
TestWithQuery
+ TestWithJsonInputAndBlobOutput
TestThatReturnsError
TestAuth
TestWithOtherStatusCode
@@ -27,6 +28,17 @@ service TestControllerService {
operation TestWithOtherStatusCode {
}
+@auth([])
+@http(method: "POST", uri: "/jsoninput/bloboutput", code: 200)
+operation TestWithJsonInputAndBlobOutput {
+ input:= {
+ @httpPayload
+ @required
+ body: JsonInput
+ }
+ output: BlobResponse
+}
+
@auth([])
@http(method: "POST", uri: "/blob", code: 200)
operation TestWithBlob {
@@ -134,6 +146,12 @@ structure TestResponseBody {
bodyMessage: String
}
+
+structure JsonInput {
+ @required
+ message: String
+}
+
@http(method: "GET", uri: "/auth", code: 200)
operation TestAuth {
}
diff --git a/smithy4playTest/testSpecs/XmlController.smithy b/smithy4playTest/testSpecs/XmlController.smithy
index 9daa33e2..5d6397b9 100644
--- a/smithy4playTest/testSpecs/XmlController.smithy
+++ b/smithy4playTest/testSpecs/XmlController.smithy
@@ -15,6 +15,8 @@ service XmlControllerDef {
operation XmlTestWithInputAndOutput {
input: XmlTestInput
output := {
+ @httpHeader("content-type")
+ contentType: String
@required
@httpPayload
body: XmlTestOutput
@@ -22,6 +24,8 @@ operation XmlTestWithInputAndOutput {
}
structure XmlTestInput {
+ @httpHeader("content-type")
+ contentType: String
@httpLabel
@required
xmlTest: String