diff --git a/adapters/akka-http/src/main/scala/caliban/AkkaHttpAdapter.scala b/adapters/akka-http/src/main/scala/caliban/AkkaHttpAdapter.scala index b8de22c165..11820ef6e2 100644 --- a/adapters/akka-http/src/main/scala/caliban/AkkaHttpAdapter.scala +++ b/adapters/akka-http/src/main/scala/caliban/AkkaHttpAdapter.scala @@ -11,6 +11,7 @@ import sttp.capabilities.WebSockets import sttp.capabilities.akka.AkkaStreams import sttp.capabilities.akka.AkkaStreams.Pipe import sttp.model.StatusCode +import sttp.monad.{ FutureMonad, MonadError } import sttp.tapir.Codec.JsonCodec import sttp.tapir.PublicEndpoint import sttp.tapir.model.ServerRequest @@ -22,6 +23,8 @@ import zio.stream.ZStream import scala.concurrent.{ ExecutionContext, Future } class AkkaHttpAdapter private (private val options: AkkaHttpServerOptions)(implicit ec: ExecutionContext) { + private implicit val monadErrorFuture: MonadError[Future] = new FutureMonad + private val akkaInterpreter = AkkaHttpServerInterpreter(options)(ec) def makeHttpService[R, E]( @@ -67,9 +70,7 @@ class AkkaHttpAdapter private (private val options: AkkaHttpServerOptions)(impli */ def makeGraphiqlService(apiPath: String): Route = akkaInterpreter.toRoute( - HttpInterpreter - .makeGraphiqlEndpoint(apiPath) - .serverLogic[Future](Future.successful) + HttpInterpreter.makeGraphiqlEndpoint[Future](apiPath) ) private implicit def streamConstructor(implicit diff --git a/adapters/http4s/src/main/scala/caliban/Http4sAdapter.scala b/adapters/http4s/src/main/scala/caliban/Http4sAdapter.scala index 9a1c6e682e..e595fc76e8 100644 --- a/adapters/http4s/src/main/scala/caliban/Http4sAdapter.scala +++ b/adapters/http4s/src/main/scala/caliban/Http4sAdapter.scala @@ -13,6 +13,7 @@ import sttp.capabilities.fs2.Fs2Streams import sttp.capabilities.zio.ZioStreams import sttp.tapir.Codec.JsonCodec import sttp.tapir.Endpoint +import sttp.tapir.integ.cats.effect.CatsMonadError import sttp.tapir.server.ServerEndpoint import sttp.tapir.server.http4s.Http4sServerInterpreter import sttp.tapir.server.http4s.ztapir.ZHttp4sServerInterpreter @@ -59,12 +60,12 @@ object Http4sAdapter { * * @see [[https://github.com/graphql/graphiql/tree/main/examples/graphiql-cdn]] */ - def makeGraphiqlService[F[_]: Async](apiPath: String): HttpRoutes[F] = + def makeGraphiqlService[F[_]: Async](apiPath: String): HttpRoutes[F] = { + implicit val F: CatsMonadError[F] = new CatsMonadError[F] Http4sServerInterpreter().toRoutes( - HttpInterpreter - .makeGraphiqlEndpoint(apiPath) - .serverLogic[F](Async[F].pure) + HttpInterpreter.makeGraphiqlEndpoint[F](apiPath) ) + } def makeWebSocketService[R, R1 <: R, E]( builder: WebSocketBuilder2[RIO[R, *]], diff --git a/adapters/pekko-http/src/main/scala/caliban/PekkoHttpAdapter.scala b/adapters/pekko-http/src/main/scala/caliban/PekkoHttpAdapter.scala index ed4fb25845..519db6f828 100644 --- a/adapters/pekko-http/src/main/scala/caliban/PekkoHttpAdapter.scala +++ b/adapters/pekko-http/src/main/scala/caliban/PekkoHttpAdapter.scala @@ -11,6 +11,7 @@ import sttp.capabilities.WebSockets import sttp.capabilities.pekko.PekkoStreams import sttp.capabilities.pekko.PekkoStreams.Pipe import sttp.model.StatusCode +import sttp.monad.{ FutureMonad, MonadError } import sttp.tapir.Codec.JsonCodec import sttp.tapir.PublicEndpoint import sttp.tapir.model.ServerRequest @@ -22,6 +23,8 @@ import zio.stream.ZStream import scala.concurrent.{ ExecutionContext, Future } class PekkoHttpAdapter private (val options: PekkoHttpServerOptions)(implicit ec: ExecutionContext) { + private implicit val monadErrorFuture: MonadError[Future] = new FutureMonad + private val pekkoInterpreter = PekkoHttpServerInterpreter(options)(ec) def makeHttpService[R, E]( @@ -66,11 +69,7 @@ class PekkoHttpAdapter private (val options: PekkoHttpServerOptions)(implicit ec * @see [[https://github.com/graphql/graphiql/tree/main/examples/graphiql-cdn]] */ def makeGraphiqlService(apiPath: String): Route = - pekkoInterpreter.toRoute( - HttpInterpreter - .makeGraphiqlEndpoint(apiPath) - .serverLogic[Future](Future.successful) - ) + pekkoInterpreter.toRoute(HttpInterpreter.makeGraphiqlEndpoint[Future](apiPath)) private implicit def streamConstructor(implicit runtime: Runtime[Any], diff --git a/adapters/play/src/main/scala/caliban/PlayAdapter.scala b/adapters/play/src/main/scala/caliban/PlayAdapter.scala index a99c9c3d8f..ac6d18ab8d 100644 --- a/adapters/play/src/main/scala/caliban/PlayAdapter.scala +++ b/adapters/play/src/main/scala/caliban/PlayAdapter.scala @@ -10,6 +10,7 @@ import sttp.capabilities.WebSockets import sttp.capabilities.pekko.PekkoStreams import sttp.capabilities.pekko.PekkoStreams.Pipe import sttp.model.StatusCode +import sttp.monad.FutureMonad import sttp.tapir.Codec.JsonCodec import sttp.tapir.PublicEndpoint import sttp.tapir.model.ServerRequest @@ -44,12 +45,10 @@ class PlayAdapter private (private val options: Option[PlayServerOptions]) { * * @see [[https://github.com/graphql/graphiql/tree/main/examples/graphiql-cdn]] */ - def makeGraphiqlService(apiPath: String)(implicit materializer: Materializer): Routes = - playInterpreter.toRoutes( - HttpInterpreter - .makeGraphiqlEndpoint(apiPath) - .serverLogic[Future](Future.successful) - ) + def makeGraphiqlService(apiPath: String)(implicit materializer: Materializer): Routes = { + implicit val F: FutureMonad = new FutureMonad()(materializer.executionContext) + playInterpreter.toRoutes(HttpInterpreter.makeGraphiqlEndpoint[Future](apiPath)) + } def makeWebSocketService[R, E]( interpreter: WebSocketInterpreter[R, E] diff --git a/interop/tapir/src/main/scala/caliban/interop/tapir/HttpInterpreter.scala b/interop/tapir/src/main/scala/caliban/interop/tapir/HttpInterpreter.scala index 2d089076db..5ec84984da 100644 --- a/interop/tapir/src/main/scala/caliban/interop/tapir/HttpInterpreter.scala +++ b/interop/tapir/src/main/scala/caliban/interop/tapir/HttpInterpreter.scala @@ -4,6 +4,7 @@ import caliban._ import caliban.interop.tapir.TapirAdapter._ import sttp.capabilities.Streams import sttp.model.{ headers => _, _ } +import sttp.monad.MonadError import sttp.shared.Identity import sttp.tapir.Codec.JsonCodec import sttp.tapir._ @@ -222,16 +223,18 @@ object HttpInterpreter { * * @see [[https://github.com/graphql/graphiql/tree/main/examples/graphiql-cdn]] */ - def makeGraphiqlEndpoint(apiPath: String): Endpoint[Unit, Right[Nothing, String], Nothing, String, Any] = { + def makeGraphiqlEndpoint[F[_]]( + apiPath: String + )(implicit F: MonadError[F]): ServerEndpoint.Full[Unit, Unit, ServerRequest, Nothing, String, Any, F] = { val apiPath0 = apiPath.split("/").filter(_.nonEmpty).mkString("/", "/", "") infallibleEndpoint.get - .in(extractFromRequest(_.pathSegments)) + .in(extractFromRequest(identity)) .out(htmlBodyUtf8) - .mapIn { segments => - val uiPath = segments.mkString("/", "/", "") - Right(HttpUtils.graphiqlHtml(apiPath = apiPath0, uiPath = uiPath)) - }( - _.value.split("/").filter(_.nonEmpty).toList - ) + .serverLogic[F] { req => + val segments = req.pathSegments + val uiPath = segments.mkString("/", "/", "") + val entity = Right(HttpUtils.graphiqlHtml(apiPath = apiPath0, uiPath = uiPath)) + F.unit(entity) + } } }