diff --git a/adapters/quick/src/main/scala/caliban/quick/package.scala b/adapters/quick/src/main/scala/caliban/quick/package.scala index e635b44c1c..405a8dbea5 100644 --- a/adapters/quick/src/main/scala/caliban/quick/package.scala +++ b/adapters/quick/src/main/scala/caliban/quick/package.scala @@ -1,8 +1,8 @@ package caliban import caliban.Configurator.ExecutionConfiguration +import zio._ import zio.http._ -import zio.{ RIO, Trace, ZIO } package object quick { @@ -68,6 +68,49 @@ package object quick { trace: Trace ): ZIO[R, CalibanError.ValidationError, RequestHandler[R, Response]] = gql.interpreter.map(QuickAdapter(_).configure(config).handler) + + /** + * Unsafe API which allows running the server impurely + */ + def unsafe: UnsafeApi[R] = gql.interpreterEither.fold(throw _, new UnsafeApi(_)) } + final class UnsafeApi[R]( + interpreter: GraphQLInterpreter[R, Any], + executionConfig: ExecutionConfiguration = ExecutionConfiguration() + ) { + + /** + * Convenience method for impurely running the server. + * + * Useful for scripts / demos / showing off Caliban to your colleagues etc. + * + * Note that in order to call this method, you need to provide all dependencies required by the GraphQL environment. You can do that by passing a `ZLayer` to [[provideLayer]]. + */ + def runServer( + port: Int = 8080, + apiPath: String = "/graphql", + graphiqlPath: Option[String] = Some("/graphiql"), + uploadPath: Option[String] = None + )(implicit trace: Trace, ev: Any =:= R): Unit = { + val run: RIO[R, Nothing] = + QuickAdapter(interpreter) + .configure(executionConfig) + .runServer(port, apiPath, graphiqlPath, uploadPath) + + ZIOApp.fromZIO(run.asInstanceOf[RIO[Any, Nothing]]).main(Array.empty) + } + + def provideLayer(layer: ZLayer[Any, Any, R]): UnsafeApi[Any] = + new UnsafeApi(interpreter.provideLayer(layer)) + + def provideSomeLayer[R0](layer: ZLayer[R0, Any, R])(implicit tag: Tag[R]): UnsafeApi[R0] = + new UnsafeApi(interpreter.provideSomeLayer(layer)) + + def configure(cfg: ExecutionConfiguration): UnsafeApi[R] = + new UnsafeApi(interpreter, cfg) + + def configureWith(cfg: ExecutionConfiguration => ExecutionConfiguration): UnsafeApi[R] = + new UnsafeApi(interpreter, cfg(executionConfig)) + } } diff --git a/core/src/main/scala/caliban/GraphQL.scala b/core/src/main/scala/caliban/GraphQL.scala index d888b5f84b..7de0f7f00d 100644 --- a/core/src/main/scala/caliban/GraphQL.scala +++ b/core/src/main/scala/caliban/GraphQL.scala @@ -58,12 +58,10 @@ trait GraphQL[-R] { self => * adding some middleware around the query execution. * Fails with a [[caliban.CalibanError.ValidationError]] if the schema is invalid. */ - final def interpreter(implicit trace: Trace): IO[ValidationError, GraphQLInterpreter[R, CalibanError]] = { - val i = cachedInterpreter - ZIO.fromEither(i) - } + final def interpreter(implicit trace: Trace): IO[ValidationError, GraphQLInterpreter[R, CalibanError]] = + ZIO.fromEither(interpreterEither) - private lazy val cachedInterpreter = + private[caliban] final lazy val interpreterEither = Validator.validateSchemaEither(schemaBuilder).map { schema => new GraphQLInterpreter[R, CalibanError] { private val rootType =