Skip to content

Commit

Permalink
Update zio-http to RC7 (#2230)
Browse files Browse the repository at this point in the history
* Update ZIO http to use latest snapshot

* Update to latest snapshot

* Fix compilation errors

* Disable autoTrace in QuickAdapter

* Use RC7
  • Loading branch information
kyri-petrou authored May 17, 2024
1 parent 1c17243 commit e7836ab
Show file tree
Hide file tree
Showing 13 changed files with 106 additions and 40 deletions.
3 changes: 3 additions & 0 deletions adapters/quick/src/main/scala/caliban/GraphiQLHandler.scala
Original file line number Diff line number Diff line change
@@ -1,8 +1,11 @@
package caliban

import zio.Trace
import zio.http._
import zio.stacktracer.TracingImplicits.disableAutoTrace

object GraphiQLHandler {
private implicit val trace: Trace = Trace.empty

/**
* Creates a handler which serves the GraphiQL UI from CDN.
Expand Down
26 changes: 19 additions & 7 deletions adapters/quick/src/main/scala/caliban/QuickAdapter.scala
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,11 @@ package caliban
import caliban.Configurator.ExecutionConfiguration
import zio._
import zio.http._
import zio.stacktracer.TracingImplicits.disableAutoTrace

final class QuickAdapter[-R] private (requestHandler: QuickRequestHandler[R]) {
final class QuickAdapter[R] private (requestHandler: QuickRequestHandler[R]) {

private implicit val trace: Trace = Trace.empty

/**
* Converts this adapter to a [[QuickHandlers]] which contains [[zio.http.RequestHandler]]s for manually constructing zio-http routes
Expand All @@ -20,19 +23,19 @@ final class QuickAdapter[-R] private (requestHandler: QuickRequestHandler[R]) {
Handler.fromFunctionZIO[Request](requestHandler.handleHttpRequest)

/**
* Converts this adapter to an `HttpApp` serving the GraphQL API at the specified path.
* Converts this adapter to an `Routes` serving the GraphQL API at the specified path.
*
* @param apiPath The path where the GraphQL API will be served.
* @param graphiqlPath The path where the GraphiQL UI will be served. If None, GraphiQL will not be served.
* @param uploadPath The path where files can be uploaded. If None, uploads will be disabled.
* @param webSocketPath The path where websocket requests will be set. If None, websocket-based subscriptions will be disabled.
*/
def toApp(
def routes(
apiPath: String,
graphiqlPath: Option[String] = None,
uploadPath: Option[String] = None,
webSocketPath: Option[String] = None
): HttpApp[R] = {
): Routes[R, Nothing] = {
val apiRoutes = List(
RoutePattern(Method.POST, apiPath) -> handlers.api,
RoutePattern(Method.GET, apiPath) -> handlers.api
Expand All @@ -46,9 +49,18 @@ final class QuickAdapter[-R] private (requestHandler: QuickRequestHandler[R]) {
val wsRoute = webSocketPath.toList.map { wsPath =>
RoutePattern(Method.ANY, wsPath) -> handlers.webSocket
}
Routes.fromIterable(apiRoutes ::: graphiqlRoute ::: uploadRoute ::: wsRoute).toHttpApp
Routes.fromIterable(apiRoutes ::: graphiqlRoute ::: uploadRoute ::: wsRoute)
}

@deprecated("Use `routes` instead", "2.6.1")
def toApp(
apiPath: String,
graphiqlPath: Option[String] = None,
uploadPath: Option[String] = None,
webSocketPath: Option[String] = None
): HttpApp[R] =
HttpApp(routes(apiPath, graphiqlPath, uploadPath, webSocketPath))

/**
* Runs the server using the default zio-http server configuration on the specified port.
* This is meant as a convenience method for getting started quickly
Expand All @@ -65,9 +77,9 @@ final class QuickAdapter[-R] private (requestHandler: QuickRequestHandler[R]) {
graphiqlPath: Option[String] = None,
uploadPath: Option[String] = None,
webSocketPath: Option[String] = None
)(implicit trace: Trace): RIO[R, Nothing] =
)(implicit trace: Trace, tag: Tag[R]): RIO[R, Nothing] =
Server
.serve[R](toApp(apiPath, graphiqlPath = graphiqlPath, uploadPath = uploadPath, webSocketPath = webSocketPath))
.serve[R](routes(apiPath, graphiqlPath = graphiqlPath, uploadPath = uploadPath, webSocketPath = webSocketPath))
.provideSomeLayer[R](Server.defaultWithPort(port))

def configure(config: ExecutionConfiguration)(implicit trace: Trace): QuickAdapter[R] =
Expand Down
6 changes: 5 additions & 1 deletion adapters/quick/src/main/scala/caliban/QuickHandlers.scala
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
package caliban

import zio.Trace
import zio.http.{ HandlerAspect, RequestHandler }
import zio.stacktracer.TracingImplicits.disableAutoTrace

final case class QuickHandlers[-R](
api: RequestHandler[R, Nothing],
Expand All @@ -11,11 +13,13 @@ final case class QuickHandlers[-R](
/**
* Applies a ZIO HTTP `HandlerAspect` to both the api and upload handlers
*/
def @@[R1 <: R](aspect: HandlerAspect[R1, Unit]): QuickHandlers[R1] =
def @@[R1 <: R](aspect: HandlerAspect[R1, Unit]): QuickHandlers[R1] = {
implicit val trace: Trace = Trace.empty
QuickHandlers(
api = (api @@ aspect).merge,
upload = (upload @@ aspect).merge,
webSocket = (webSocket @@ aspect).merge
)
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ package caliban.quick
import caliban.ws.WebSocketHooks
import zio._
import zio.http.{ WebSocketConfig => ZWebSocketConfig }
import zio.stacktracer.TracingImplicits.disableAutoTrace

case class WebSocketConfig[-R](
keepAliveTime: Option[Duration],
Expand Down
50 changes: 45 additions & 5 deletions adapters/quick/src/main/scala/caliban/quick/package.scala
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ package caliban
import caliban.Configurator.ExecutionConfiguration
import zio._
import zio.http._
import zio.stacktracer.TracingImplicits.disableAutoTrace

package object quick {

Expand All @@ -25,7 +26,8 @@ package object quick {
uploadPath: Option[String] = None,
webSocketPath: Option[String] = None
)(implicit
trace: Trace
trace: Trace,
tag: Tag[R]
): RIO[R, Nothing] =
gql.interpreter.flatMap(
QuickAdapter(_).runServer(
Expand All @@ -38,12 +40,29 @@ package object quick {
)

/**
* Creates zio-http `HttpApp` from the GraphQL API
* Creates zio-http `Routes` from the GraphQL API
*
* @param apiPath The route to serve the API on, e.g., `/api/graphql`
* @param graphiqlPath Optionally define a route to serve the GraphiQL UI on, e.g., `/graphiql`
* @param uploadPath Optionally define a route to serve file uploads on, e.g., `/api/upload`
* @param webSocketPath The path where websocket requests will be set. If None, websocket-based subscriptions will be disabled.
*/
def routes(
apiPath: String,
graphiqlPath: Option[String] = None,
uploadPath: Option[String] = None,
webSocketPath: Option[String] = None
)(implicit trace: Trace): Task[Routes[R, Nothing]] =
gql.interpreter.map(
QuickAdapter(_).routes(
apiPath = apiPath,
graphiqlPath = graphiqlPath,
uploadPath = uploadPath,
webSocketPath = webSocketPath
)
)

@deprecated("use `routes` instead", "2.6.1")
def toApp(
apiPath: String,
graphiqlPath: Option[String] = None,
Expand Down Expand Up @@ -88,14 +107,35 @@ package object quick {
/**
* Unsafe API which allows running the server impurely
*/
def unsafe: UnsafeApi[R] = gql.interpreterEither.fold(throw _, new UnsafeApi(_))
def unsafe: UnsafeApi[R] = new UnsafeApi[R](gql.interpreterUnsafe)
}

final class UnsafeApi[R](
interpreter: GraphQLInterpreter[R, Any],
executionConfig: ExecutionConfiguration = ExecutionConfiguration()
) {

/**
* Creates zio-http `Routes` from the GraphQL API
*
* @param apiPath The route to serve the API on, e.g., `/api/graphql`
* @param graphiqlPath Optionally define a route to serve the GraphiQL UI on, e.g., `/graphiql`
* @param uploadPath Optionally define a route to serve file uploads on, e.g., `/api/upload`
* @param webSocketPath The path where websocket requests will be set. If None, websocket-based subscriptions will be disabled.
*/
def routes(
apiPath: String,
graphiqlPath: Option[String] = None,
uploadPath: Option[String] = None,
webSocketPath: Option[String] = None
): Routes[R, Any] =
QuickAdapter(interpreter).routes(
apiPath = apiPath,
graphiqlPath = graphiqlPath,
uploadPath = uploadPath,
webSocketPath = webSocketPath
)

/**
* Convenience method for impurely running the server.
*
Expand All @@ -108,11 +148,11 @@ package object quick {
apiPath: String = "/graphql",
graphiqlPath: Option[String] = Some("/graphiql"),
uploadPath: Option[String] = None
)(implicit trace: Trace, ev: Any =:= R): Unit = {
)(implicit trace: Trace, tag: Tag[R], ev: Any =:= R): Unit = {
val run: RIO[R, Nothing] =
QuickAdapter(interpreter)
.configure(executionConfig)
.runServer(port, apiPath, graphiqlPath, uploadPath)
.provideSomeLayer[R](ZLayer.scoped[Any](Configurator.set(executionConfig)))

ZIOApp.fromZIO(run.asInstanceOf[RIO[Any, Nothing]]).main(Array.empty)
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ object QuickAdapterSpec extends ZIOSpecDefault {
private val apiLayer = envLayer >>> ZLayer.fromZIO {
for {
app <- TestApi.api
.toApp("/api/graphql", uploadPath = Some("/upload/graphql"), webSocketPath = Some("/ws/graphql"))
.routes("/api/graphql", uploadPath = Some("/upload/graphql"), webSocketPath = Some("/ws/graphql"))
.map(_ @@ auth)
_ <- Server.serve(app).forkScoped
_ <- Live.live(Clock.sleep(3 seconds))
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ object ZHttpAdapterSpec extends ZIOSpecDefault {
),
Method.ANY / "ws" / "graphql" ->
ZHttpAdapter.makeWebSocketService(WebSocketInterpreter(interpreter))
).toHttpApp
)
)
.forkScoped
_ <- Live.live(Clock.sleep(3 seconds))
Expand Down
2 changes: 1 addition & 1 deletion build.sbt
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ val zioInteropReactiveVersion = "2.0.2"
val zioConfigVersion = "3.0.7"
val zqueryVersion = "0.7.1"
val zioJsonVersion = "0.6.2"
val zioHttpVersion = "3.0.0-RC6"
val zioHttpVersion = "3.0.0-RC7"
val zioOpenTelemetryVersion = "3.0.0-RC21"
val zioPreludeVersion = "1.0.0-RC26"

Expand Down
21 changes: 15 additions & 6 deletions core/src/main/scala/caliban/Configurator.scala
Original file line number Diff line number Diff line change
Expand Up @@ -27,26 +27,35 @@ object Configurator {
queryExecution: QueryExecution = QueryExecution.Parallel,
validations: List[QueryValidation] = AllValidations,
queryCache: UIO[Cache] = Cache.empty(Trace.empty)
)
) { self =>

/**
* Creates a ZLayer that can be used to set this configuration at the application level
*/
def toLayer: ULayer[Unit] = ZLayer.scoped(set(self))
}

private val configRef: FiberRef[ExecutionConfiguration] =
Unsafe.unsafe(implicit u => FiberRef.unsafe.make(ExecutionConfiguration()))

private[caliban] val configuration: UIO[ExecutionConfiguration] =
configRef.get

private[caliban] def setWith[R, E, A](cfg: ExecutionConfiguration)(f: ZIO[R, E, A])(implicit
trace: Trace
): ZIO[R, E, A] =
configRef.locally(cfg)(f)

private[caliban] def locallyWith[R, E, A](
cfg: ExecutionConfiguration => ExecutionConfiguration
)(
f: ZIO[R, E, A]
): ZIO[R, E, A] =
configRef.locallyWith(cfg)(f)

private[caliban] def set(cfg: ExecutionConfiguration): URIO[Scope, Unit] =
configRef.locallyScoped(cfg)

private[caliban] def setWith[R, E, A](cfg: ExecutionConfiguration)(f: ZIO[R, E, A])(implicit
trace: Trace
): ZIO[R, E, A] =
configRef.locally(cfg)(f)

/**
* Skip validation of the query.
* @param skip if true, the query will not be validated (in that case, the `validations` field is ignored).
Expand Down
2 changes: 1 addition & 1 deletion examples/src/main/scala/example/quick/AuthExampleApp.scala
Original file line number Diff line number Diff line change
Expand Up @@ -67,7 +67,7 @@ object AuthExampleApp extends ZIOAppDefault {
Routes(
Method.POST / "api" / "graphql" -> handlers.api,
Method.GET / "graphiql" -> graphiqlHandler
).toHttpApp
)
)
_ <- ZIO.logInfo(s"Server started on port $port")
_ <- ZIO.never
Expand Down
15 changes: 7 additions & 8 deletions examples/src/main/scala/example/ziohttp/AuthExampleApp.scala
Original file line number Diff line number Diff line change
Expand Up @@ -93,15 +93,14 @@ object AuthExampleApp extends ZIOAppDefault {
(for {
exampleApi <- ZIO.service[GraphQL[Any]]
interpreter <- (exampleApi |+| Authed.api).interpreter
port <- Server
.install(
Routes(
Method.ANY / "api" / "graphql" ->
ZHttpAdapter.makeHttpService(HttpInterpreter(interpreter)) @@ Auth.middleware,
Method.ANY / "ws" / "graphql" -> Auth.WebSockets.live(interpreter),
Method.ANY / "graphiql" -> graphiql
).toHttpApp
port <- Server.install(
Routes(
Method.ANY / "api" / "graphql" ->
ZHttpAdapter.makeHttpService(HttpInterpreter(interpreter)) @@ Auth.middleware,
Method.ANY / "ws" / "graphql" -> Auth.WebSockets.live(interpreter),
Method.ANY / "graphiql" -> graphiql
)
)
_ <- ZIO.logInfo(s"Server started on port $port")
_ <- ZIO.never
} yield ())
Expand Down
14 changes: 6 additions & 8 deletions examples/src/main/scala/example/ziohttp/ExampleApp.scala
Original file line number Diff line number Diff line change
Expand Up @@ -19,15 +19,13 @@ object ExampleApp extends ZIOAppDefault {
(for {
interpreter <- ZIO.serviceWithZIO[GraphQL[Any]](_.interpreter)
_ <-
Server
.serve(
Routes(
Method.ANY / "api" / "graphql" -> ZHttpAdapter.makeHttpService(HttpInterpreter(interpreter)),
Method.ANY / "ws" / "graphql" ->
ZHttpAdapter.makeWebSocketService(WebSocketInterpreter(interpreter)),
Method.ANY / "graphiql" -> graphiql
).toHttpApp
Server.serve(
Routes(
Method.ANY / "api" / "graphql" -> ZHttpAdapter.makeHttpService(HttpInterpreter(interpreter)),
Method.ANY / "ws" / "graphql" -> ZHttpAdapter.makeWebSocketService(WebSocketInterpreter(interpreter)),
Method.ANY / "graphiql" -> graphiql
)
)
_ <- Console.printLine("Server online at http://localhost:8088/")
_ <- Console.printLine("Press RETURN to stop...") *> Console.readLine
} yield ())
Expand Down
2 changes: 1 addition & 1 deletion vuepress/docs/docs/adapters.md
Original file line number Diff line number Diff line change
Expand Up @@ -166,7 +166,7 @@ for {
Method.GET / "graphiql" -> graphiql,
Method.POST / "upload" / "graphql" -> handlers.upload
// Add more routes, apply middleware, etc.
).toHttpApp
)
_ <- Server.serve(app).provide(Server.defaultWithPort(8080))
} yield ()
```
Expand Down

0 comments on commit e7836ab

Please sign in to comment.