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 fbd7dedc65..3071f6f394 100644 --- a/interop/tapir/src/main/scala/caliban/interop/tapir/HttpInterpreter.scala +++ b/interop/tapir/src/main/scala/caliban/interop/tapir/HttpInterpreter.scala @@ -19,21 +19,24 @@ sealed trait HttpInterpreter[-R, E] { self => serverRequest: ServerRequest )(implicit streamConstructor: StreamConstructor[BS]): ZIO[R, TapirResponse, CalibanResponse[BS]] - def serverEndpoints[R1 <: R, S](stream: Streams[S])(implicit - streamConstructor: StreamConstructor[stream.BinaryStream] - ): List[CalibanEndpoint[R1, stream.BinaryStream, S]] = { + def serverEndpoints[R1 <: R, S](streams: Streams[S])(implicit + streamConstructor: StreamConstructor[streams.BinaryStream] + ): List[CalibanEndpoint[R1, streams.BinaryStream, S]] = { def logic( request: (GraphQLRequest, ServerRequest) - ): RIO[R1, Either[TapirResponse, CalibanResponse[stream.BinaryStream]]] = { + ): RIO[R1, Either[TapirResponse, CalibanResponse[streams.BinaryStream]]] = { val (graphQLRequest, serverRequest) = request executeRequest(graphQLRequest, serverRequest).either } - endpoints[S](stream).map(_.serverLogic(logic(_))) + endpoints[S](streams).map(_.serverLogic(logic(_))) } def intercept[R1](interceptor: Interceptor[R1, R]): HttpInterpreter[R1, E] = HttpInterpreter.Intercepted(self, interceptor) + def prependPath(path: List[String]): HttpInterpreter[R, E] = + HttpInterpreter.Prepended(self, path) + def configure[R1](configurator: Configurator[R1]): HttpInterpreter[R & R1, E] = intercept[R & R1](ZLayer.scopedEnvironment[R & R1 & ServerRequest](configurator *> ZIO.environment[R])) } @@ -63,6 +66,33 @@ object HttpInterpreter { } } + private case class Prepended[R, E]( + interpreter: HttpInterpreter[R, E], + path: List[String] + ) extends HttpInterpreter[R, E] { + override def endpoints[S]( + streams: Streams[S] + ): List[ + PublicEndpoint[(GraphQLRequest, ServerRequest), TapirResponse, CalibanResponse[streams.BinaryStream], S] + ] = { + val endpoints = interpreter.endpoints(streams) + if (path.nonEmpty) { + val p: List[EndpointInput[Unit]] = path.map(stringToPath) + val fixedPath: EndpointInput[Unit] = p.tail.foldLeft(p.head)(_ / _) + + endpoints.map(_.prependIn(fixedPath)) + } else { + endpoints + } + } + + def executeRequest[BS]( + graphQLRequest: GraphQLRequest, + serverRequest: ServerRequest + )(implicit streamConstructor: StreamConstructor[BS]): ZIO[R, TapirResponse, CalibanResponse[BS]] = + interpreter.executeRequest(graphQLRequest, serverRequest) + } + private case class Intercepted[R1, R, E]( interpreter: HttpInterpreter[R, E], layer: ZLayer[R1 & ServerRequest, TapirResponse, R] diff --git a/interop/tapir/src/main/scala/caliban/interop/tapir/HttpUploadInterpreter.scala b/interop/tapir/src/main/scala/caliban/interop/tapir/HttpUploadInterpreter.scala index a8b11c30ce..d6109aadfd 100644 --- a/interop/tapir/src/main/scala/caliban/interop/tapir/HttpUploadInterpreter.scala +++ b/interop/tapir/src/main/scala/caliban/interop/tapir/HttpUploadInterpreter.scala @@ -84,6 +84,9 @@ sealed trait HttpUploadInterpreter[-R, E] { self => def intercept[R1](interceptor: Interceptor[R1, R]): HttpUploadInterpreter[R1, E] = HttpUploadInterpreter.Intercepted(self, interceptor) + def prependPath(path: List[String]): HttpUploadInterpreter[R, E] = + HttpUploadInterpreter.Prepended(self, path) + def configure[R1](configurator: Configurator[R1]): HttpUploadInterpreter[R & R1, E] = intercept[R & R1](ZLayer.scopedEnvironment[R & R1 & ServerRequest](configurator *> ZIO.environment[R])) } @@ -123,6 +126,31 @@ object HttpUploadInterpreter { interpreter.executeRequest(graphQLRequest, serverRequest).provideSome[R1](ZLayer.succeed(serverRequest), layer) } + private case class Prepended[R, E]( + interpreter: HttpUploadInterpreter[R, E], + path: List[String] + ) extends HttpUploadInterpreter[R, E] { + override def endpoint[S]( + streams: Streams[S] + ): PublicEndpoint[UploadRequest, TapirResponse, CalibanResponse[streams.BinaryStream], S] = { + val endpoints = interpreter.endpoint(streams) + if (path.nonEmpty) { + val p: List[EndpointInput[Unit]] = path.map(stringToPath) + val fixedPath: EndpointInput[Unit] = p.tail.foldLeft(p.head)(_ / _) + + endpoints.prependIn(fixedPath) + } else { + endpoints + } + } + + def executeRequest[BS]( + graphQLRequest: GraphQLRequest, + serverRequest: ServerRequest + )(implicit streamConstructor: StreamConstructor[BS]): ZIO[R, TapirResponse, CalibanResponse[BS]] = + interpreter.executeRequest(graphQLRequest, serverRequest) + } + def apply[R, E]( interpreter: GraphQLInterpreter[R, E] )(implicit responseValueCodec: JsonCodec[ResponseValue]): HttpUploadInterpreter[R, E] = diff --git a/interop/tapir/src/main/scala/caliban/interop/tapir/WebSocketInterpreter.scala b/interop/tapir/src/main/scala/caliban/interop/tapir/WebSocketInterpreter.scala index 90be964f8b..07d2cfe46b 100644 --- a/interop/tapir/src/main/scala/caliban/interop/tapir/WebSocketInterpreter.scala +++ b/interop/tapir/src/main/scala/caliban/interop/tapir/WebSocketInterpreter.scala @@ -28,6 +28,9 @@ sealed trait WebSocketInterpreter[-R, E] { self => def intercept[R1](interceptor: Interceptor[R1, R]): WebSocketInterpreter[R1, E] = WebSocketInterpreter.Intercepted(self, interceptor) + def prependPath(path: List[String]): WebSocketInterpreter[R, E] = + WebSocketInterpreter.Prepended(self, path) + def configure[R1](configurator: Configurator[R1]): WebSocketInterpreter[R & R1, E] = intercept[R & R1](ZLayer.scopedEnvironment[R & R1 & ServerRequest](configurator *> ZIO.environment[R])) } @@ -74,6 +77,28 @@ object WebSocketInterpreter { .catchAll(ZIO.left(_)) } + private case class Prepended[R, E]( + interpreter: WebSocketInterpreter[R, E], + path: List[String] + ) extends WebSocketInterpreter[R, E] { + val endpoint: PublicEndpoint[(ServerRequest, String), TapirResponse, (String, CalibanPipe), ZioWebSockets] = { + if (path.nonEmpty) { + val p: List[EndpointInput[Unit]] = path.map(stringToPath) + val fixedPath: EndpointInput[Unit] = p.tail.foldLeft(p.head)(_ / _) + + interpreter.endpoint.prependIn(fixedPath) + } else { + interpreter.endpoint + } + } + + def makeProtocol( + serverRequest: ServerRequest, + protocol: String + ): URIO[R, Either[TapirResponse, (String, CalibanPipe)]] = + interpreter.makeProtocol(serverRequest, protocol) + } + def apply[R, E]( interpreter: GraphQLInterpreter[R, E], keepAliveTime: Option[Duration] = None,