All Downloads are FREE. Search and download functionalities are using the official Maven repository.

caliban.reporting.SchemaReporter.scala Maven / Gradle / Ivy

The newest version!
package caliban.reporting

import caliban.client.CalibanClientError.CommunicationError
import caliban.reporting.ReportingError.{ ClientError, RetryableError }
import sttp.client3.SttpBackend
import sttp.client3.UriContext
import zio._

trait SchemaReporter {
  def report[A](ref: SchemaReportingRef[A], withCoreSchema: Boolean): IO[ReportingError, ReportingResponse]
}

object SchemaReporter {

  def make(accessToken: String): ZIO[SttpClient, Nothing, SchemaReporter] = for {
    client <- ZIO.service[SttpClient]
  } yield new SchemaReporter {
    import caliban.reporting.client.{ Mutation, ReportSchemaError, ReportSchemaResponse, SchemaReport }

    private final val REPORTING_URL = "https://schema-reporting.api.apollographql.com"

    private val onReportSchemaError = (
      ReportSchemaError.withCoreSchema ~
        ReportSchemaError.code.map(_.value) ~
        ReportSchemaError.message ~
        ReportSchemaError.inSeconds.map(_.seconds)
    ).mapN(ReportingError.SchemaError(_, _, _, _))

    private val onReportSchemaResponse = (
      ReportSchemaResponse.withCoreSchema ~
        ReportSchemaResponse.inSeconds.map(_.seconds)
    ).mapN(ReportingResponse.apply(_, _))

    private def reportSchemaMutation(coreSchema: Option[String], report: SchemaReport) =
      Mutation.reportSchema(coreSchema, report)(
        onReportSchemaError = onReportSchemaError.map(Left(_)),
        onReportSchemaResponse = onReportSchemaResponse.map(Right(_))
      )

    override def report[A](ref: SchemaReportingRef[A], withCoreSchema: Boolean): IO[ReportingError, ReportingResponse] =
      ref.coreSchema.get.flatMap { coreSchema =>
        val renderedSchema = ref.renderSchema(coreSchema)
        Util.hashSchema(renderedSchema).flatMap { hash =>
          client
            .send(
              reportSchemaMutation(
                coreSchema = if (withCoreSchema) Some(renderedSchema) else None,
                SchemaReport(
                  bootId = ref.bootId.toString,
                  coreSchemaHash = hash,
                  graphRef = ref.graphRef,
                  libraryVersion = ref.libraryVersion,
                  platform = ref.platform,
                  runtimeVersion = ref.runtimeVersion,
                  serverId = ref.serverId,
                  userVersion = ref.userVersion
                )
              )
                .toRequest(uri"$REPORTING_URL/api/graphql", useVariables = true)
                .header("X-API-Key", accessToken)
            )
        }
      }
        .mapError(error => RetryableError(error))
        .flatMap { response =>
          response.body match {
            case Left(error @ CommunicationError(_, _)) => ZIO.fail(RetryableError(error))
            case Left(error)                            => ZIO.fail(ClientError(error))
            case Right(Some(Left(error)))               => ZIO.fail(error)
            case Right(Some(Right(value)))              => ZIO.succeed(value)
            // Should never come here
            case Right(None)                            =>
              ZIO.dieMessage("You should never see this error, as it indicates there is something wrong with Caliban!")
          }
        }
  }

  def fromConfig[R: Tag](
    f: R => String
  ): ZLayer[R with SttpClient, Nothing, SchemaReporter] =
    fromConfigZIO[R, Nothing]((r: R) => ZIO.succeed(f(r)))

  def fromConfigZIO[R: Tag, E](
    f: R => IO[E, String]
  ): ZLayer[SttpClient with R, E, SchemaReporter] = ZLayer {
    for {
      accessToken <- ZIO.serviceWithZIO[R](f)
      reporter    <- make(accessToken)
    } yield reporter
  }

  def fromDefaultConfig: ZLayer[SttpClient with System, Throwable, SchemaReporter] =
    fromConfigZIO[System, Throwable](
      _.env("APOLLO_KEY")
        .someOrFail(
          new Exception(
            "No environment variable found for `APOLLO_KEY`. You must define this value with your token in order to use the default configuration."
          )
        )
    )
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy