Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Improve UX for constructing a Caliban interpreter via interop #2130

Merged
merged 3 commits into from
Feb 23, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 10 additions & 1 deletion core/src/main/scala/caliban/GraphQL.scala
Original file line number Diff line number Diff line change
Expand Up @@ -58,11 +58,20 @@ trait GraphQL[-R] { self =>
* Creates an interpreter from your API. A GraphQLInterpreter is a wrapper around your API that allows
* adding some middleware around the query execution.
* Fails with a [[caliban.CalibanError.ValidationError]] if the schema is invalid.
*
* @see [[interpreterEither]] for a variant that returns an Either instead, making it easier to embed in non-ZIO applications
*/
final def interpreter(implicit trace: Trace): IO[ValidationError, GraphQLInterpreter[R, CalibanError]] =
ZIO.fromEither(interpreterEither)

private[caliban] final lazy val interpreterEither =
/**
* Creates an interpreter from your API. A GraphQLInterpreter is a wrapper around your API that allows
* adding some middleware around the query execution.
* Returns a `Left` containing the schema validation error if the schema is invalid.
*
* @see [[interpreter]] for a ZIO variant of this method that makes it easier to embed in ZIO applications
*/
final lazy val interpreterEither: Either[ValidationError, GraphQLInterpreter[R, CalibanError]] =
Validator.validateSchemaEither(schemaBuilder).map { schema =>
new GraphQLInterpreter[R, CalibanError] {
private val rootType =
Expand Down
2 changes: 1 addition & 1 deletion examples/src/main/scala/example/http4s/ExampleAppF.scala
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ object ExampleAppF extends IOApp {
override def run(args: List[String]): IO[ExitCode] =
Dispatcher.parallel[IO].use { implicit dispatcher =>
for {
interpreter <- ExampleApi.makeApi(exampleService).interpreterAsync[IO]
interpreter <- ExampleApi.makeApi(exampleService).interpreterF[IO]
_ <- EmberServerBuilder
.default[IO]
.withHost(host"localhost")
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -94,7 +94,7 @@ object ContextualCatsInterop extends IOApp {
}

for {
interpreter <- api.interpreterAsync[F]
interpreter <- api.interpreterF[F]
_ <- interpreter.checkAsync[F](query)
_ <- Logger[F].info("Executing request")
result <- interpreter.executeAsync[F](query)(interop).local[LogContext](_.child("execute-request"))
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -96,7 +96,7 @@ object ContextualCatsInteropIO extends IOApp {
}

for {
interpreter <- api.interpreterAsync[IO]
interpreter <- api.interpreterF[IO]
_ <- interpreter.checkAsync[IO](query)
_ <- log.info("Executing request")
result <- locally(interpreter.executeAsync[IO](query)(interop))(_.child("execute-request"))
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -67,7 +67,7 @@ object ExampleCatsInterop extends IOApp.Simple {
val api = graphQL(RootResolver(Some(queries), Option.empty[Unit], Some(subscriptions)))

for {
interpreter <- api.interpreterAsync[IO]
interpreter <- api.interpreterF[IO]

_ <- console.println("execute a query:")
_ <- interpreter.checkAsync[IO](query)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@ object ExampleMonixInterop extends TaskApp {

override def run(args: List[String]): Task[ExitCode] =
for {
interpreter <- api.interpreterAsync
interpreter <- api.interpreterMonix
_ <- interpreter.checkAsync(query)
result <- interpreter.executeAsync(query)
_ <- Task.eval(println(result.data))
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import caliban.introspection.adt.__Type
import caliban.schema.Step.QueryStep
import caliban.schema.{ Schema, Step }
import caliban._
import cats.Monad
import cats.{ ApplicativeThrow, Monad }
import cats.effect.Async
import cats.effect.std.Dispatcher
import zio.query.ZQuery
Expand Down Expand Up @@ -176,11 +176,15 @@ object CatsInterop {
)(query: String)(implicit interop: ToEffect[F, Any]): F[Unit] =
interop.toEffect(graphQL.check(query))

@deprecated("use interpreterF instead")
def interpreterAsync[F[_], R](
graphQL: GraphQL[R]
)(implicit interop: ToEffect[F, Any]): F[GraphQLInterpreter[R, CalibanError]] =
interop.toEffect(graphQL.interpreter)

def interpreterF[F[_]: ApplicativeThrow, R](graphQL: GraphQL[R]): F[GraphQLInterpreter[R, CalibanError]] =
ApplicativeThrow[F].fromEither(graphQL.interpreterEither)

def schema[F[_], R, A](implicit interop: FromEffect[F, R], ev: Schema[R, A]): Schema[R, F[A]] =
new Schema[R, F[A]] {
override def toType(isInput: Boolean, isSubscription: Boolean): __Type =
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ package caliban.interop.cats
import caliban.execution.QueryExecution
import caliban.schema.Schema
import caliban.{ CalibanError, GraphQL, GraphQLInterpreter, GraphQLResponse, InputValue }
import cats.ApplicativeThrow

package object implicits {

Expand All @@ -25,8 +26,12 @@ package object implicits {
}

implicit class CatsEffectGraphQL[R](private val underlying: GraphQL[R]) extends AnyVal {
@deprecated("Use interpreterF instead")
def interpreterAsync[F[_]](implicit interop: ToEffect[F, Any]): F[GraphQLInterpreter[R, CalibanError]] =
CatsInterop.interpreterAsync[F, R](underlying)

def interpreterF[F[_]: ApplicativeThrow]: F[GraphQLInterpreter[R, CalibanError]] =
CatsInterop.interpreterF[F, R](underlying)
}

implicit def catsEffectSchema[F[_], R, A](implicit interop: FromEffect[F, R], ev: Schema[R, A]): Schema[R, F[A]] =
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -30,10 +30,16 @@ object MonixInterop {
)(query: String)(implicit runtime: Runtime[Any]): MonixTask[Unit] =
graphQL.check(query).toMonixTask

@deprecated("Use interpreterMonix instead")
def interpreterAsync[R](
graphQL: GraphQL[R]
)(implicit runtime: Runtime[Any]): MonixTask[GraphQLInterpreter[R, CalibanError]] =
graphQL.interpreter.toMonixTask
interpreterMonix(graphQL)

def interpreterMonix[R](
graphQL: GraphQL[R]
): MonixTask[GraphQLInterpreter[R, CalibanError]] =
MonixTask.fromEither(graphQL.interpreterEither)

implicit final class ExtraZioEffectOps[-R, +A](private val effect: ZIO[R, Throwable, A]) extends AnyVal {
def toMonixTask(implicit zioRuntime: Runtime[R]): MonixTask[A] =
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,8 +23,12 @@ package object implicits {
}

implicit class MonixGraphQL[R, E](underlying: GraphQL[R]) {
@deprecated("use interpreterMonix instead")
def interpreterAsync(implicit runtime: Runtime[Any]): Task[GraphQLInterpreter[R, CalibanError]] =
MonixInterop.interpreterAsync(underlying)

def interpreterMonix: Task[GraphQLInterpreter[R, CalibanError]] =
MonixInterop.interpreterMonix(underlying)
}

implicit def monixEffectSchema[R, A](implicit ev: Schema[R, A], ev2: ConcurrentEffect[Task]): Schema[R, Task[A]] =
Expand Down