diff --git a/doc/server/ziohttp.md b/doc/server/ziohttp.md index 00ada39417..f28a1769f8 100644 --- a/doc/server/ziohttp.md +++ b/doc/server/ziohttp.md @@ -45,7 +45,7 @@ example: import sttp.tapir.PublicEndpoint import sttp.tapir.ztapir._ import sttp.tapir.server.ziohttp.ZioHttpInterpreter -import zio.http.{HttpApp, Request, Response} +import zio.http.{Request, Response, Routes} import zio._ def countCharacters(s: String): ZIO[Any, Nothing, Int] = @@ -54,7 +54,7 @@ def countCharacters(s: String): ZIO[Any, Nothing, Int] = val countCharactersEndpoint: PublicEndpoint[String, Unit, Int, Any] = endpoint.in(stringBody).out(plainBody[Int]) -val countCharactersHttp: HttpApp[Any] = +val countCharactersHttp: Routes[Any, Response] = ZioHttpInterpreter().toHttp(countCharactersEndpoint.zServerLogic(countCharacters)) ``` diff --git a/examples2/src/main/scala/sttp/tapir/examples2/security/ServerSecurityLogicZio.scala b/examples2/src/main/scala/sttp/tapir/examples2/security/ServerSecurityLogicZio.scala index f7b030f647..37c41191e2 100644 --- a/examples2/src/main/scala/sttp/tapir/examples2/security/ServerSecurityLogicZio.scala +++ b/examples2/src/main/scala/sttp/tapir/examples2/security/ServerSecurityLogicZio.scala @@ -5,7 +5,7 @@ import sttp.client3.asynchttpclient.zio.AsyncHttpClientZioBackend import sttp.model.HeaderNames import sttp.tapir.server.ziohttp.ZioHttpInterpreter import sttp.tapir.ztapir._ -import zio.http.{HttpApp, Server} +import zio.http.{Response => ZioHttpResponse, Routes, Server} import zio.{Console, ExitCode, IO, Scope, Task, ZIO, ZIOAppDefault, ZLayer} object ServerSecurityLogicZio extends ZIOAppDefault { @@ -55,7 +55,7 @@ object ServerSecurityLogicZio extends ZIOAppDefault { // --- // interpreting as an app - val routes: HttpApp[Any] = ZioHttpInterpreter().toHttp(secureHelloWorldWithLogic) + val routes: Routes[Any, ZioHttpResponse] = ZioHttpInterpreter().toHttp(secureHelloWorldWithLogic) override def run: ZIO[Scope, Throwable, ExitCode] = { def testWith(backend: SttpBackend[Task, Any], port: Int, path: String, salutation: String, token: String): Task[String] = diff --git a/project/Versions.scala b/project/Versions.scala index f27eadc397..932a6b2a8d 100644 --- a/project/Versions.scala +++ b/project/Versions.scala @@ -36,7 +36,7 @@ object Versions { val iron = "2.5.0" val enumeratum = "1.7.3" val zio = "2.1.1" - val zioHttp = "3.0.0-RC6" + val zioHttp = "3.0.0-RC7" val zioInteropCats = "23.0.0.8" val zioInteropReactiveStreams = "2.0.2" val zioJson = "0.6.2" diff --git a/server/zio-http-server/src/main/scala/sttp/tapir/server/ziohttp/ZioHttpInterpreter.scala b/server/zio-http-server/src/main/scala/sttp/tapir/server/ziohttp/ZioHttpInterpreter.scala index ecfc28cfb3..87aa855748 100644 --- a/server/zio-http-server/src/main/scala/sttp/tapir/server/ziohttp/ZioHttpInterpreter.scala +++ b/server/zio-http-server/src/main/scala/sttp/tapir/server/ziohttp/ZioHttpInterpreter.scala @@ -15,10 +15,10 @@ import zio.http.{Header => ZioHttpHeader, Headers => ZioHttpHeaders, _} trait ZioHttpInterpreter[R] { def zioHttpServerOptions: ZioHttpServerOptions[R] = ZioHttpServerOptions.default - def toHttp[R2](se: ZServerEndpoint[R2, ZioStreams with WebSockets]): HttpApp[R & R2] = + def toHttp[R2](se: ZServerEndpoint[R2, ZioStreams with WebSockets]): Routes[R & R2, Response] = toHttp(List(se)) - def toHttp[R2](ses: List[ZServerEndpoint[R2, ZioStreams with WebSockets]]): HttpApp[R & R2] = { + def toHttp[R2](ses: List[ZServerEndpoint[R2, ZioStreams with WebSockets]]): Routes[R & R2, Response] = { implicit val bodyListener: ZioHttpBodyListener[R & R2] = new ZioHttpBodyListener[R & R2] implicit val monadError: MonadError[RIO[R & R2, *]] = new RIOMonadError[R & R2] val widenedSes = ses.map(_.widen[R & R2]) @@ -27,42 +27,40 @@ trait ZioHttpInterpreter[R] { val zioHttpResponseBody = new ZioHttpToResponseBody val interceptors = RejectInterceptor.disableWhenSingleEndpoint(widenedServerOptions.interceptors, widenedSes) - HttpApp( - Routes.singleton { - Handler.fromFunctionZIO[(Path, Request)] { case (_: Path, request: Request) => - val interpreter = new ServerInterpreter[ZioStreams with WebSockets, RIO[R & R2, *], ZioResponseBody, ZioStreams]( - FilterServerEndpoints(widenedSes), - zioHttpRequestBody, - zioHttpResponseBody, - interceptors, - zioHttpServerOptions.deleteFile - ) + Routes.singleton { + Handler.fromFunctionZIO[(Path, Request)] { case (_: Path, request: Request) => + val interpreter = new ServerInterpreter[ZioStreams with WebSockets, RIO[R & R2, *], ZioResponseBody, ZioStreams]( + FilterServerEndpoints(widenedSes), + zioHttpRequestBody, + zioHttpResponseBody, + interceptors, + zioHttpServerOptions.deleteFile + ) - if (request.url.encode.trim.isEmpty) { - ZIO.logError("Received an apparently empty request URI, not handling: " + request) *> - ZIO.fail(Response.internalServerError("Empty request URI")) - } else { - val serverRequest = ZioHttpServerRequest(request) - interpreter - .apply(serverRequest) - .foldCauseZIO( - cause => ZIO.logErrorCause(cause) *> ZIO.fail(Response.internalServerError(cause.squash.getMessage)), - { - case RequestResult.Response(resp) => - resp.body match { - case None => handleHttpResponse(resp, None) - case Some(Right(body)) => handleHttpResponse(resp, Some(body)) - case Some(Left(body)) => handleWebSocketResponse(body, zioHttpServerOptions.customWebSocketConfig(serverRequest)) - } + if (request.url.encode.trim.isEmpty) { + ZIO.logError("Received an apparently empty request URI, not handling: " + request) *> + ZIO.fail(Response.internalServerError("Empty request URI")) + } else { + val serverRequest = ZioHttpServerRequest(request) + interpreter + .apply(serverRequest) + .foldCauseZIO( + cause => ZIO.logErrorCause(cause) *> ZIO.fail(Response.internalServerError(cause.squash.getMessage)), + { + case RequestResult.Response(resp) => + resp.body match { + case None => handleHttpResponse(resp, None) + case Some(Right(body)) => handleHttpResponse(resp, Some(body)) + case Some(Left(body)) => handleWebSocketResponse(body, zioHttpServerOptions.customWebSocketConfig(serverRequest)) + } - case RequestResult.Failure(_) => - ZIO.fail(Response.notFound) - } - ) - } + case RequestResult.Failure(_) => + ZIO.fail(Response.notFound) + } + ) } } - ) + } } private def handleWebSocketResponse( diff --git a/server/zio-http-server/src/test/scala/sttp/tapir/server/ziohttp/ZioHttpCompositionTest.scala b/server/zio-http-server/src/test/scala/sttp/tapir/server/ziohttp/ZioHttpCompositionTest.scala index 530ee1376a..afc252c00b 100644 --- a/server/zio-http-server/src/test/scala/sttp/tapir/server/ziohttp/ZioHttpCompositionTest.scala +++ b/server/zio-http-server/src/test/scala/sttp/tapir/server/ziohttp/ZioHttpCompositionTest.scala @@ -7,7 +7,7 @@ import sttp.client3._ import sttp.model.StatusCode import sttp.tapir.server.tests.CreateServerTest import sttp.tapir.ztapir._ -import zio.http.{endpoint => _, _} +import zio.http.{Response => ZioHttpResponse, endpoint => _, _} import zio.{Task, ZIO} class ZioHttpCompositionTest( @@ -15,7 +15,7 @@ class ZioHttpCompositionTest( Task, Any, ZioHttpServerOptions[Any], - HttpApp[Any] + Routes[Any, ZioHttpResponse] ] ) { import createServerTest._ @@ -26,9 +26,9 @@ class ZioHttpCompositionTest( val ep1 = endpoint.get.in("p1").zServerLogic[Any](_ => ZIO.unit) val ep3 = endpoint.get.in("p3").zServerLogic[Any](_ => ZIO.fail(new RuntimeException("boom"))) - val route1: HttpApp[Any] = ZioHttpInterpreter().toHttp(ep1) - val route2: HttpApp[Any] = Routes(Method.GET / "p2" -> handler(zio.http.Response.ok)).toHttpApp - val route3: HttpApp[Any] = ZioHttpInterpreter().toHttp(ep3) + val route1: Routes[Any, ZioHttpResponse] = ZioHttpInterpreter().toHttp(ep1) + val route2: Routes[Any, ZioHttpResponse] = Routes(Method.GET / "p2" -> handler(ZioHttpResponse.ok)) + val route3: Routes[Any, ZioHttpResponse] = ZioHttpInterpreter().toHttp(ep3) NonEmptyList.of(route3, route1, route2) } diff --git a/server/zio-http-server/src/test/scala/sttp/tapir/server/ziohttp/ZioHttpTestServerInterpreter.scala b/server/zio-http-server/src/test/scala/sttp/tapir/server/ziohttp/ZioHttpTestServerInterpreter.scala index abe306f3e9..d1070b0fe5 100644 --- a/server/zio-http-server/src/test/scala/sttp/tapir/server/ziohttp/ZioHttpTestServerInterpreter.scala +++ b/server/zio-http-server/src/test/scala/sttp/tapir/server/ziohttp/ZioHttpTestServerInterpreter.scala @@ -18,18 +18,18 @@ class ZioHttpTestServerInterpreter( channelFactory: ZLayer[Any, Nothing, ChannelFactory[ServerChannel]] )(implicit trace: Trace -) extends TestServerInterpreter[Task, ZioStreams with WebSockets, ZioHttpServerOptions[Any], HttpApp[Any]] { +) extends TestServerInterpreter[Task, ZioStreams with WebSockets, ZioHttpServerOptions[Any], Routes[Any, Response]] { override def route( es: List[ServerEndpoint[ZioStreams with WebSockets, Task]], interceptors: Interceptors - ): HttpApp[Any] = { + ): Routes[Any, Response] = { val serverOptions: ZioHttpServerOptions[Any] = interceptors(ZioHttpServerOptions.customiseInterceptors).options ZioHttpInterpreter(serverOptions).toHttp(es) } override def serverWithStop( - routes: NonEmptyList[HttpApp[Any]], + routes: NonEmptyList[Routes[Any, Response]], gracefulShutdownTimeout: Option[FiniteDuration] ): Resource[IO, (Port, KillSwitch)] = { implicit val r: Runtime[Any] = Runtime.default