sangria.schema.Schema Scala Examples

The following examples show how to use sangria.schema.Schema. You can vote up the ones you like or vote down the ones you don't like, and go to the original project or source file by following the links above each example.
Example 1
Source File: MutationCallbackSchemaExecutor.scala    From graphcool-framework   with Apache License 2.0 5 votes vote down vote up
package cool.graph.deprecated.actions

import com.typesafe.scalalogging.LazyLogging
import cool.graph.client.ClientInjector
import cool.graph.client.database.{DeferredResolverProvider, SimpleManyModelDeferredResolver, SimpleToManyDeferredResolver}
import cool.graph.cuid.Cuid.createCuid
import cool.graph.deprecated.actions.schemas.{ActionUserContext, MutationMetaData}
import cool.graph.shared.models.{Model, Project}
import cool.graph.shared.schema.JsonMarshalling._
import sangria.execution.Executor
import sangria.parser.QueryParser
import sangria.schema.Schema
import spray.json.{JsObject, JsString}

import scala.concurrent.ExecutionContext.Implicits.global
import scala.concurrent.Future
import scala.util.{Failure, Success}

case class Event(id: String, url: String, payload: Option[JsObject])

class MutationCallbackSchemaExecutor(project: Project,
                                     model: Model,
                                     schema: Schema[ActionUserContext, Unit],
                                     nodeId: String,
                                     fragment: String,
                                     url: String,
                                     mutationId: String)(implicit injector: ClientInjector)
    extends LazyLogging {
  def execute: Future[Event] = {
    implicit val inj = injector.toScaldi

    val dataFut = QueryParser.parse(fragment) match {
      case Success(queryAst) =>
        Executor.execute(
          schema,
          queryAst,
          deferredResolver = new DeferredResolverProvider(
            new SimpleToManyDeferredResolver,
            new SimpleManyModelDeferredResolver,
            skipPermissionCheck = true
          ),
          userContext = ActionUserContext(
            requestId = "",
            project = project,
            nodeId = nodeId,
            mutation = MutationMetaData(id = mutationId, _type = "Create"),
            log = (x: String) => logger.info(x)
          )
        )
      case Failure(error) =>
        Future.successful(JsObject("error" -> JsString(error.getMessage)))
    }

    dataFut
      .map {
        case JsObject(dataMap) => Event(id = createCuid(), url = url, payload = Some(dataMap("data").asJsObject))
        case json              => sys.error(s"Must only receive JsObjects here. But got instead: ${json.compactPrint}")
      }

  }
} 
Example 2
Source File: SchemaProvider.scala    From graphql-gateway   with Apache License 2.0 5 votes vote down vote up
package sangria.gateway.schema

import akka.NotUsed
import akka.stream.scaladsl.Source
import better.files.File
import io.circe.Json
import sangria.execution.{Executor, Middleware}
import sangria.execution.deferred.DeferredResolver
import sangria.schema.Schema

import scala.concurrent.{Await, Future}

trait SchemaProvider[Ctx, Val] {
  def schemaInfo: Future[Option[SchemaInfo[Ctx, Val]]]
  def schemaChanges: Option[Source[Boolean, NotUsed]]
}

case class SchemaInfo[Ctx, Val](
  schema: Schema[Ctx, Val],
  ctx: Ctx,
  value: Val,
  middleware: List[Middleware[Ctx]],
  deferredResolver: DeferredResolver[Ctx] = DeferredResolver.empty,
  schemaRendered: String,
  schemaIntrospection: Json,
  files: Vector[File]) 
Example 3
Source File: SchemaLoader.scala    From graphql-gateway   with Apache License 2.0 5 votes vote down vote up
package sangria.gateway.schema

import better.files.File
import sangria.ast.Document
import sangria.execution.Executor
import sangria.execution.deferred.DeferredResolver
import sangria.gateway.AppConfig
import sangria.gateway.file.FileUtil
import sangria.gateway.http.client.HttpClient
import sangria.gateway.schema.materializer.{GatewayContext, GatewayMaterializer}
import sangria.gateway.util.Logging
import sangria.parser.QueryParser
import sangria.schema.Schema
import sangria.marshalling.circe._

import scala.concurrent.{ExecutionContext, Future}
import scala.util.control.NonFatal
import scala.util.{Failure, Success}

class SchemaLoader(config: AppConfig, client: HttpClient, mat: GatewayMaterializer)(implicit ec: ExecutionContext) extends Logging {
  def loadSchema: Future[Option[SchemaInfo[GatewayContext, Any]]] = {
    val files = FileUtil.loadFiles(config.watch.allFiles, config.watch.allGlobs)

    if (files.nonEmpty) {
      val parsed =
        files.map {
          case (path, content) ⇒ path → QueryParser.parse(content)
        }

      val failed = parsed.collect {case (path, Failure(e)) ⇒ path → e}

      if (failed.nonEmpty) {
        failed.foreach { case (path, error) ⇒
          logger.error(s"Can't parse file '$path':\n${error.getMessage}")
        }

        Future.successful(None)
      } else {
        val successful = parsed.collect {case (path, Success(doc)) ⇒ path → doc}
        val document = Document.merge(successful.map(_._2))

        try {
          val info =
            for {
              ctx ← GatewayContext.loadContext(config, client, document)
              schema = Schema.buildFromAst(document, mat.schemaBuilder(ctx).validateSchemaWithException(document))
              intro ← executeIntrospection(schema, ctx)
            } yield Some(SchemaInfo(
              schema,
              ctx,
              (),
              Nil,
              DeferredResolver.empty,
              schema.renderPretty,
              intro,
              files.map(_._1)))

          info.recover(handleError(files))
        } catch {
          case e if handleError(files).isDefinedAt(e) ⇒
            Future.successful(handleError(files)(e))
        }
      }
    } else {
      logger.error("No schema files found!")
      Future.successful(None)
    }
  }

  private def handleError(files: Vector[(File, String)]): PartialFunction[Throwable, Option[SchemaInfo[GatewayContext, Any]]] = {
    case NonFatal(e) ⇒
      logger.error(s"Can't create the schema from files: ${files.map(_._1).mkString(", ")}. " + e.getMessage)
      None
  }

  private def executeIntrospection(schema: Schema[GatewayContext, Any], ctx: GatewayContext) =
    Executor.execute(schema, sangria.introspection.introspectionQuery(schemaDescription = false, directiveRepeatableFlag = false), ctx)
} 
Example 4
Source File: GraphQLSuperMicroService.scala    From cornichon   with Apache License 2.0 5 votes vote down vote up
package com.github.agourlay.cornichon.framework.examples.superHeroes.server

import cats.data.Validated
import cats.data.Validated.{ Invalid, Valid }
import sangria.macros.derive._
import sangria.schema.Schema
import sangria.schema._
import sangria.marshalling.circe._
import io.circe.generic.auto._

class GraphQLSuperMicroService(sm: SuperMicroService) {

  def publisherByName(sessionId: String, name: String): Option[Publisher] =
    unpack(sm.publisherByName(sessionId, name))

  def superheroByName(sessionId: String, name: String, protectIdentity: Boolean = false): Option[SuperHero] =
    unpack(sm.superheroByName(sessionId, name, protectIdentity))

  def updateSuperhero(sessionId: String, s: SuperHero): Option[SuperHero] =
    unpack(sm.updateSuperhero(sessionId, s))

  private def unpack[A](v: Validated[ApiError, A]): Option[A] =
    v match {
      case Valid(p) => Some(p)
      case Invalid(e) => e match {
        case SessionNotFound(_)   => None
        case PublisherNotFound(_) => None
        case SuperHeroNotFound(_) => None
        case _                    => throw new RuntimeException(e.msg)
      }
    }
}

object GraphQlSchema {

  implicit val PublisherType = deriveObjectType[Unit, Publisher](
    ObjectTypeDescription("A comics publisher.")
  )

  implicit val SuperHeroType = deriveObjectType[Unit, SuperHero](
    ObjectTypeDescription("A superhero.")
  )

  implicit val PublisherInputType = deriveInputObjectType[Publisher](
    InputObjectTypeName("PublisherInput")
  )

  implicit val SuperHeroInputType = deriveInputObjectType[SuperHero](
    InputObjectTypeName("SuperHeroInput")
  )

  val QueryType = deriveObjectType[Unit, GraphQLSuperMicroService](
    ObjectTypeName("Root"),
    ObjectTypeDescription("Gateway to awesomeness."),
    IncludeMethods("publisherByName", "superheroByName")
  )

  val MutationType = deriveObjectType[Unit, GraphQLSuperMicroService](
    ObjectTypeName("RootMut"),
    ObjectTypeDescription("Gateway to mutation awesomeness!"),
    IncludeMethods("updateSuperhero")
  )

  val SuperHeroesSchema = Schema(QueryType, Some(MutationType))
} 
Example 5
Source File: ActionSchemaResolver.scala    From graphcool-framework   with Apache License 2.0 5 votes vote down vote up
package cool.graph.system

import com.typesafe.scalalogging.LazyLogging
import cool.graph.DataItem
import cool.graph.Types.Id
import cool.graph.client.schema.simple.SimpleSchemaModelObjectTypeBuilder
import cool.graph.deprecated.actions.schemas._
import cool.graph.shared.{ApiMatrixFactory}
import cool.graph.shared.models.{ActionTriggerMutationModelMutationType, ActionTriggerMutationRelationMutationType, ActionTriggerType, Project}
import sangria.execution.Executor
import sangria.introspection.introspectionQuery
import sangria.marshalling.sprayJson._
import sangria.schema.Schema
import scaldi.{Injectable, Injector}
import spray.json.JsObject

import scala.concurrent.ExecutionContext.Implicits.global
import scala.concurrent.Future

case class ActionSchemaPayload(
    triggerType: ActionTriggerType.Value,
    mutationModel: Option[ActionSchemaPayloadMutationModel],
    mutationRelation: Option[ActionSchemaPayloadMutationRelation]
)

case class ActionSchemaPayloadMutationModel(
    modelId: Id,
    mutationType: ActionTriggerMutationModelMutationType.Value
)

case class ActionSchemaPayloadMutationRelation(
    relationId: Id,
    mutationType: ActionTriggerMutationRelationMutationType.Value
)

class ActionSchemaResolver(implicit inj: Injector) extends Injectable with LazyLogging {

  def resolve(project: Project, payload: ActionSchemaPayload): Future[String] = {
    val apiMatrix = inject[ApiMatrixFactory].create(project)

    payload.triggerType match {
      case ActionTriggerType.MutationModel =>
        val model = apiMatrix.filterModel(project.getModelById_!(payload.mutationModel.get.modelId))

        model match {
          case None =>
            Future.successful(JsObject.empty.prettyPrint)
          case Some(model) =>
            val modelObjectTypes = new SimpleSchemaModelObjectTypeBuilder(project)

            val schema: Schema[ActionUserContext, Unit] =
              payload.mutationModel.get.mutationType match {
                case ActionTriggerMutationModelMutationType.Create =>
                  new CreateSchema(model = model, modelObjectTypes = modelObjectTypes, project = project).build()
                case ActionTriggerMutationModelMutationType.Update =>
                  new UpdateSchema(model = model,
                                   modelObjectTypes = modelObjectTypes,
                                   project = project,
                                   updatedFields = List(),
                                   previousValues = DataItem("dummy", Map())).build()
                case ActionTriggerMutationModelMutationType.Delete =>
                  new DeleteSchema(model = model, modelObjectTypes = modelObjectTypes, project = project).build()
              }

            Executor
              .execute(
                schema = schema,
                queryAst = introspectionQuery,
                userContext = ActionUserContext(
                  requestId = "",
                  project = project,
                  nodeId = model.id,
                  mutation = MutationMetaData(id = "", _type = ""),
                  log = (x: String) => logger.info(x)
                )
              )
              .map { response =>
                val JsObject(fields) = response
                fields("data").compactPrint
              }
        }
    }
  }
} 
Example 6
Source File: AlgoliaSchema.scala    From graphcool-framework   with Apache License 2.0 5 votes vote down vote up
package cool.graph.shared.algolia.schemas

import cool.graph.client.SangriaQueryArguments
import cool.graph.client.schema.SchemaModelObjectTypesBuilder
import cool.graph.shared.algolia.AlgoliaContext
import cool.graph.shared.models.{Model, Project}
import cool.graph.{DataItem, FilteredResolver}
import sangria.schema.{Context, Field, ObjectType, OptionType, Schema}
import scaldi.{Injectable, Injector}

import scala.concurrent.{ExecutionContextExecutor, Future}

class AlgoliaSchema[ManyDataItemType](project: Project, model: Model, modelObjectTypes: SchemaModelObjectTypesBuilder[ManyDataItemType])(
    implicit injector: Injector)
    extends Injectable {

  implicit val dispatcher = inject[ExecutionContextExecutor](identified by "dispatcher")

  def resolve[ManyDataItemType](ctx: Context[AlgoliaContext, Unit]): Future[Option[DataItem]] = {
    FilteredResolver.resolve(modelObjectTypes, model, ctx.ctx.nodeId, ctx, ctx.ctx.dataResolver)
  }

  val algoliaSyncField: Field[AlgoliaContext, Unit] = Field(
    "node",
    description = Some("The model to synchronize with Algolia."),
    arguments = List(SangriaQueryArguments.filterArgument(model = model, project = project)),
    fieldType = OptionType(modelObjectTypes.modelObjectTypes(model.name)),
    resolve = (ctx) => resolve(ctx)
  )

  def build(): Schema[AlgoliaContext, Unit] = {
    val Query = ObjectType(
      "Query",
      List(algoliaSyncField)
    )

    Schema(Query)
  }
} 
Example 7
Source File: AlgoliaFullModelSchema.scala    From graphcool-framework   with Apache License 2.0 5 votes vote down vote up
package cool.graph.shared.algolia.schemas

import cool.graph.Types.DataItemFilterCollection
import cool.graph.client.database.QueryArguments
import cool.graph.client.SangriaQueryArguments
import cool.graph.client.schema.SchemaModelObjectTypesBuilder
import cool.graph.shared.algolia.AlgoliaFullModelContext
import cool.graph.shared.models.{Model, Project}
import sangria.schema.{Field, ListType, ObjectType, Schema}
import scaldi.{Injectable, Injector}

import scala.concurrent.ExecutionContextExecutor

class AlgoliaFullModelSchema[ManyDataItemType](project: Project, model: Model, modelObjectTypes: SchemaModelObjectTypesBuilder[ManyDataItemType])(
    implicit injector: Injector)
    extends Injectable {

  implicit val dispatcher =
    inject[ExecutionContextExecutor](identified by "dispatcher")

  val algoliaSyncField: Field[AlgoliaFullModelContext, Unit] = Field(
    "node",
    description = Some("The table to synchronize with Algolia."),
    arguments = List(SangriaQueryArguments.filterArgument(model = model, project = project)),
    fieldType = ListType(modelObjectTypes.modelObjectTypes(model.name)),
    resolve = (ctx) => {

      val filter: DataItemFilterCollection = modelObjectTypes
        .extractQueryArgumentsFromContext(model = model, ctx = ctx)
        .flatMap(_.filter)
        .getOrElse(List())

      val arguments = Some(QueryArguments(filter = Some(filter), skip = None, after = None, first = None, before = None, last = None, orderBy = None))

      ctx.ctx.dataResolver
        .resolveByModel(model, arguments)
        .map(result => result.items)
    }
  )

  def build(): Schema[AlgoliaFullModelContext, Unit] = {
    val Query = ObjectType(
      "Query",
      List(algoliaSyncField)
    )

    Schema(Query)
  }
} 
Example 8
Source File: PermissionSchemaResolver.scala    From graphcool-framework   with Apache License 2.0 5 votes vote down vote up
package cool.graph.shared.queryPermissions

import akka.actor.ActorSystem
import akka.stream.ActorMaterializer
import com.typesafe.scalalogging.LazyLogging
import cool.graph.client.UserContext
import cool.graph.client.database.DeferredTypes.ManyModelExistsDeferred
import cool.graph.client.schema.simple.SimpleSchemaModelObjectTypeBuilder
import cool.graph.shared.{ApiMatrixFactory, models}
import cool.graph.shared.models.Project
import sangria.execution.Executor
import sangria.introspection.introspectionQuery
import sangria.schema.{Context, Field, ObjectType, Schema}
import scaldi.{Injectable, Injector}
import spray.json.JsObject

import scala.concurrent.ExecutionContext.Implicits.global
import scala.concurrent.Future

class PermissionSchemaResolver(implicit inj: Injector) extends Injectable with LazyLogging {

  import sangria.marshalling.sprayJson._

  def resolve(project: Project): Future[String] = {

    implicit val system       = inject[ActorSystem](identified by "actorSystem")
    implicit val materializer = inject[ActorMaterializer](identified by "actorMaterializer")

    val permissionSchema = PermissionSchemaResolver.permissionSchema(project)

    Executor
      .execute(
        schema = permissionSchema,
        queryAst = introspectionQuery,
        userContext = new UserContext(
          project = project,
          authenticatedRequest = None,
          requestId = "PermissionSchemaResolver-request-id",
          requestIp = "PermissionSchemaResolver-request-ip",
          clientId = "PermissionSchemaResolver-client-id",
          log = (_) => (),
          queryAst = Some(introspectionQuery)
        )
      )
      .map { response =>
        val JsObject(fields) = response
        fields("data").compactPrint
      }
  }
}

object PermissionSchemaResolver extends Injectable {
  def permissionSchema(project: Project)(implicit inj: Injector): Schema[UserContext, Unit] = {
    val apiMatrix      = inject[ApiMatrixFactory].create(project)
    val includedModels = project.models.filter(model => apiMatrix.includeModel(model.name))
    val schemaBuilder  = new SimpleSchemaModelObjectTypeBuilder(project, None)

    def getConnectionArguments(model: models.Model) = {
      schemaBuilder.mapToListConnectionArguments(model)
    }

    def resolveGetAllItemsQuery(model: models.Model, ctx: Context[UserContext, Unit]): sangria.schema.Action[UserContext, Boolean] = {
      val arguments = schemaBuilder.extractQueryArgumentsFromContext(model, ctx)

      ManyModelExistsDeferred(model, arguments)
    }

    def getModelField(model: models.Model): Field[UserContext, Unit] = {
      Field(
        s"Some${model.name.capitalize}Exists",
        fieldType = sangria.schema.BooleanType,
        arguments = getConnectionArguments(model),
        resolve = (ctx) => {
          resolveGetAllItemsQuery(model, ctx)
        }
      )
    }

    val query    = ObjectType("Query", includedModels.map(getModelField))
    val mutation = None

    Schema(query, mutation)
  }
} 
Example 9
Source File: IntrospectionQueryHandler.scala    From graphcool-framework   with Apache License 2.0 5 votes vote down vote up
package cool.graph.client.server

import cool.graph.client.{ClientInjector, UserContext}
import cool.graph.shared.models.Project
import sangria.execution.Executor
import sangria.introspection.introspectionQuery
import sangria.schema.Schema
import spray.json.JsValue

import scala.concurrent.{ExecutionContext, Future}

case class IntrospectionQueryHandler(
    project: Project,
    schema: Schema[UserContext, Unit],
    onFailureCallback: PartialFunction[Throwable, Any],
    log: String => Unit
)(implicit injector: ClientInjector, ec: ExecutionContext) {

  implicit val inj = injector.toScaldi
  def handle(requestId: String, requestIp: String, clientId: String): Future[JsValue] = {
    import cool.graph.shared.schema.JsonMarshalling._
    val context = UserContext.load(
      project = project,
      requestId = requestId,
      requestIp = requestIp,
      clientId = clientId,
      log = log
    )

    val result = Executor.execute(
      schema = schema,
      queryAst = introspectionQuery,
      userContext = context
    )
    result.onFailure(onFailureCallback)
    result
  }
} 
Example 10
Source File: QueryPermissionValidator.scala    From graphcool-framework   with Apache License 2.0 5 votes vote down vote up
package cool.graph.client.authorization.queryPermissions

import akka.actor.ActorSystem
import akka.stream.ActorMaterializer
import cool.graph.client.database.{DeferredResolverProvider, SimpleManyModelDeferredResolver, SimpleToManyDeferredResolver}
import cool.graph.client.{ClientInjector, UserContext}
import cool.graph.metrics.ClientSharedMetrics
import cool.graph.shared.errors.UserAPIErrors.InsufficientPermissions
import cool.graph.shared.models.{AuthenticatedRequest, Project}
import cool.graph.shared.queryPermissions.PermissionSchemaResolver
import sangria.ast._
import sangria.execution.deferred.DeferredResolver
import sangria.execution.{DeprecationTracker, Executor}
import sangria.marshalling.queryAst._
import sangria.marshalling.{InputUnmarshaller, QueryAstResultMarshaller}
import sangria.parser.QueryParser
import sangria.schema.Schema
import sangria.validation.QueryValidator

import scala.concurrent.ExecutionContext.Implicits.global
import scala.concurrent.Future
import scala.util.{Failure, Success}

class QueryPermissionValidator(project: Project)(implicit injector: ClientInjector, system: ActorSystem, materializer: ActorMaterializer) {

  lazy val schema: Schema[UserContext, Unit] = PermissionSchemaResolver.permissionSchema(project)(injector.toScaldi)

  lazy val deferredResolverProvider: DeferredResolver[Any] =
    new DeferredResolverProvider(new SimpleToManyDeferredResolver, new SimpleManyModelDeferredResolver, skipPermissionCheck = true)
      .asInstanceOf[DeferredResolver[Any]]

  lazy val executor = Executor(
    schema = schema.asInstanceOf[Schema[Any, Any]],
    queryValidator = QueryValidator.default,
    deferredResolver = deferredResolverProvider,
    exceptionHandler = PartialFunction.empty,
    deprecationTracker = DeprecationTracker.empty,
    middleware = Nil,
    maxQueryDepth = None,
    queryReducers = Nil
  )

  def validate(
      query: String,
      variables: Map[String, Any],
      authenticatedRequest: Option[AuthenticatedRequest],
      alwaysQueryMasterDatabase: Boolean
  ): Future[Boolean] = {
    injector.onPermissionQuery(project.id)
    ClientSharedMetrics.queryPermissionCounter.inc(project.id)

    val context = new UserContext(
      project = project,
      authenticatedRequest = authenticatedRequest,
      requestId = "grap-permission-query",
      requestIp = "graph-permission-query",
      project.ownerId,
      (x: String) => Unit,
      alwaysQueryMasterDatabase = alwaysQueryMasterDatabase
    )(injector.toScaldi)

    val dataFut: Future[QueryAstResultMarshaller#Node] =
      QueryParser.parse(query) match {
        case Success(_queryAst) =>
          executor
            .execute(queryAst = _queryAst, userContext = context, root = (), variables = InputUnmarshaller.mapVars(variables))
            .recover {
              case e: Throwable => throw InsufficientPermissions(s"Permission Query is invalid. Could not be executed. Error Message: ${e.getMessage}")
            }
        case Failure(error) =>
          throw InsufficientPermissions(s"Permission Query is invalid. Could not be parsed. Error Message: ${error.getMessage}")
      }

    dataFut.map(traverseAndCheckForLeafs)
  }

  private def traverseAndCheckForLeafs(root: AstNode): Boolean = {
    root match {
      case ObjectValue(fields, _, _)   => fields.forall(field => traverseAndCheckForLeafs(field))
      case ObjectField(_, value, _, _) => traverseAndCheckForLeafs(value)
      case x: BooleanValue             => x.value
      case _                           => sys.error(s"Received unknown type of AstNode. Could not handle: $root") //triggered by NullValue(Vector(),None)
    }
  }
} 
Example 11
Source File: GraphQLHandler.scala    From daml   with Apache License 2.0 5 votes vote down vote up
// Copyright (c) 2020 Digital Asset (Switzerland) GmbH and/or its affiliates. All rights reserved.
// SPDX-License-Identifier: Apache-2.0

package com.daml.navigator

import akka.actor.ActorRef
import akka.http.scaladsl.model.StatusCode
import akka.http.scaladsl.model.StatusCodes._
import com.daml.navigator.graphql._
import com.daml.navigator.graphql.SprayMarshallers._
import com.daml.navigator.model.PartyState
import com.daml.navigator.store.Store.StoreException
import com.typesafe.scalalogging.LazyLogging
import sangria.ast.Document
import sangria.execution._
import sangria.parser.QueryParser
import sangria.renderer.SchemaRenderer
import sangria.schema.Schema
import spray.json._

import scala.concurrent.{ExecutionContext, Future}
import scala.util.Try

case class ParseResult(ast: Document, operationName: Option[String], variables: JsValue)


trait GraphQLHandler {
  def schema: Schema[GraphQLContext, Unit]
  def parse(request: String): Try[ParseResult]
  def parse(request: JsValue): Try[ParseResult]
  def executeQuery(parsed: ParseResult, party: PartyState): Future[(StatusCode, JsValue)]
  def renderSchema: String
}

object GraphQLHandler {
  type ParseQuery = JsValue => Try[ParseResult]
  type ExecuteQuery = (ParseResult, PartyState) => Future[(StatusCode, JsValue)]
  type CustomEndpoints = Set[CustomEndpoint[_]]
}

case class DefaultGraphQLHandler(
    customEndpoints: GraphQLHandler.CustomEndpoints,
    platformStore: Option[ActorRef])(
    implicit executionContext: ExecutionContext
) extends GraphQLHandler
    with LazyLogging {

  def schema: Schema[GraphQLContext, Unit] = new GraphQLSchema(customEndpoints).QuerySchema

  def parse(request: String): Try[ParseResult] =
    Try(request.parseJson).flatMap(parse)

  def parse(request: JsValue): Try[ParseResult] =
    for {
      fields <- Try(request.asJsObject.fields)
      JsString(query) <- Try(fields("query"))
      operationName = fields.get("operationName").collect {
        case JsString(value) => value
      }
      vars: JsValue = fields.get("variables") match {
        case Some(obj: JsObject) => obj
        case _ => JsObject.empty
      }
      ast <- QueryParser.parse(query)
    } yield ParseResult(ast, operationName, vars)

  def executeQuery(parsed: ParseResult, party: PartyState): Future[(StatusCode, JsValue)] = {
    platformStore.fold[Future[(StatusCode, JsValue)]](
      Future.successful(InternalServerError -> JsString("Platform store not available"))
    )(store => {
      val context = GraphQLContext(party, store)
      Executor
        .execute(
          schema,
          parsed.ast,
          context,
          variables = parsed.variables,
          operationName = parsed.operationName,
          exceptionHandler = ExceptionHandler {
            case (_, StoreException(message)) => HandledException(message)
          }
        )
        .map(OK -> _)
        .recover {
          case error: QueryAnalysisError =>
            logger.warn(s"GraphQL analysis error ${error.getMessage}.")
            BadRequest -> error.resolveError
          case error: ErrorWithResolver =>
            logger.error("Failed to execute GraphQL query", error)
            InternalServerError -> error.resolveError
        }
    })
  }

  def renderSchema: String = SchemaRenderer.renderSchema(schema)
} 
Example 12
Source File: SangriaCodegenBaseSpec.scala    From sbt-graphql   with Apache License 2.0 5 votes vote down vote up
package rocks.muki.graphql.codegen.style.sangria

import java.io.File

import org.scalatest.wordspec.AnyWordSpec
import org.scalatest.EitherValues
import rocks.muki.graphql.codegen.{DocumentLoader, ScalametaGenerator, TypedDocumentParser}
import rocks.muki.graphql.schema.SchemaLoader
import sangria.schema.Schema
import sbt._

import scala.io.Source
import scala.meta._

abstract class SangriaCodegenBaseSpec(name: String, schema: Option[Schema[_, _]] = None)
    extends AnyWordSpec
    with EitherValues {
  def this(name: String, schema: Schema[_, _]) = this(name, Some(schema))

  val inputDir = new File("src/test/resources/sangria", name)

  def contentOf(file: File) =
    Source.fromFile(file).mkString

  "SangriaCodegen" should {
    for {
      input <- inputDir.listFiles()
      if input.getName.endsWith(".graphql")
      name = input.getName.replace(".graphql", "")
      expected = new File(inputDir, s"$name.scala")
      if expected.exists
    } {
      s"generate code for ${input.getName}" in {
        val generator = ScalametaGenerator(s"${name}Api")
        val schema =
          SchemaLoader
            .fromFile(inputDir / "schema.graphql")
            .loadSchema()

        val document = DocumentLoader.single(schema, input).right.value
        val typedDocument =
          TypedDocumentParser(schema, document).parse().right.value
        val out = generator(typedDocument).right.value

        val actual = out.show[Syntax]

        if (actual.trim != contentOf(expected).trim)
          println(actual)

        assert(actual.trim == contentOf(expected).trim)
      }
    }
  }
} 
Example 13
Source File: CodeGenContext.scala    From sbt-graphql   with Apache License 2.0 5 votes vote down vote up
package rocks.muki.graphql.codegen

import java.io.File

import sangria.schema.Schema
import sbt.Logger


case class CodeGenContext(
    schema: Schema[_, _],
    targetDirectory: File,
    graphQLFiles: Seq[File],
    packageName: String,
    moduleName: String,
    jsonCodeGen: JsonCodeGen,
    imports: Seq[String],
    preProcessors: Seq[PreProcessor],
    log: Logger
) 
Example 14
Source File: GraphQlController.scala    From tap   with Apache License 2.0 5 votes vote down vote up
package controllers

import javax.inject.Inject
import models.GraphqlSchema
import models.graphql.GraphqlActions
import play.api.Logger
import play.api.libs.json.{JsObject, JsValue, Json}
import play.api.mvc.{Action, AnyContent, InjectedController, Result}
import sangria.ast.Document
import sangria.execution.{ErrorWithResolver, Executor, QueryAnalysisError}
import sangria.marshalling.playJson.{PlayJsonInputUnmarshallerJObject, PlayJsonResultMarshaller}
import sangria.parser.{QueryParser, SyntaxError}
import sangria.schema.Schema
import views.GraphiqlPage

import scala.concurrent.ExecutionContext.Implicits.global
import scala.concurrent.Future
import scala.util.{Failure, Success}


class GraphQlController @Inject() (assets: AssetsFinder, gqlSchema: GraphqlSchema, actions: GraphqlActions) extends InjectedController {

  val schema:Schema[GraphqlActions,Unit] = gqlSchema.create

  def graphiql:Action[AnyContent] = Action {
    request => Logger.info("Got Any content request from:" + request.remoteAddress)
    //Ok(views.html.graphiql(assets))
    Ok(GraphiqlPage.render("Explore TAP with GraphiQL"))
  }

  def graphql:Action[JsValue] = Action.async(parse.json) { request =>
    val query = (request.body \ "query").as[String]
    val operation = (request.body \ "operationName").asOpt[String]
    val variables = (request.body \ "variables").asOpt[JsObject].getOrElse(Json.obj())
    Logger.info(s"Query received from ${request.remoteAddress} >>> ${operation.getOrElse("No query")}")
    Logger.info(s"Variables: $variables")
    process(query,operation,variables)
  }

  def process(query:String,name:Option[String],variables:JsObject):Future[Result] = QueryParser.parse(query) match {
    case Success(queryAst) => executeGraphQLQuery(queryAst, name, variables)
    case Failure(error: SyntaxError) => Future.successful(BadRequest(error.getMessage))
    case _ => Future.successful(BadRequest("There was a problem with the request to TAP graphql."))
  }

  def executeGraphQLQuery(query: Document, name: Option[String], vars: JsObject):Future[Result] = {
     Executor.execute(schema, query, actions, operationName = name, variables = vars)
      .map(Ok(_))
      .recover {
        case error: QueryAnalysisError => BadRequest(error.resolveError)
        case error: ErrorWithResolver => InternalServerError(error.resolveError)
      }

  }
} 
Example 15
Source File: GraphqlSchema.scala    From tap   with Apache License 2.0 5 votes vote down vote up
package models

import models.graphql.Fields._
import models.graphql.GraphqlActions
import sangria.schema.{Field, ObjectType, Schema, fields}


class GraphqlSchema {

  private val tapFields = fields[GraphqlActions,Unit](
    Field(CleanField.name,CleanField.deriveType,CleanField.description,CleanField.arguments,CleanField.resolver),
    Field(AnnotationsField.name,AnnotationsField.deriveType,AnnotationsField.description,AnnotationsField.arguments,AnnotationsField.resolver),
    Field(VocabularyField.name,VocabularyField.deriveType,VocabularyField.description,VocabularyField.arguments,VocabularyField.resolver),
    Field(MetricsField.name,MetricsField.deriveType,MetricsField.description,MetricsField.arguments,MetricsField.resolver),
    Field(PosStatsField.name,PosStatsField.deriveType,PosStatsField.description,PosStatsField.arguments,PosStatsField.resolver),
    Field(SyllablesField.name,SyllablesField.deriveType,SyllablesField.description,SyllablesField.arguments,SyllablesField.resolver),
    Field(SpellingField.name,SpellingField.deriveType,SpellingField.description,SpellingField.arguments,SpellingField.resolver),
    Field(ExpressionsField.name,ExpressionsField.deriveType,ExpressionsField.description,ExpressionsField.arguments,ExpressionsField.resolver),
    Field(ReflectExpressionsField.name,ReflectExpressionsField.deriveType,ReflectExpressionsField.description,ReflectExpressionsField.arguments,ReflectExpressionsField.resolver),
    Field(AffectExpressionsField.name,AffectExpressionsField.deriveType,AffectExpressionsField.description,AffectExpressionsField.arguments,AffectExpressionsField.resolver),
    Field(RhetoricalMovesField.name,RhetoricalMovesField.deriveType,RhetoricalMovesField.description,RhetoricalMovesField.arguments,RhetoricalMovesField.resolver),
    Field(BatchField.name,BatchField.deriveType,BatchField.description,BatchField.arguments,BatchField.resolver)
  )

  def create:Schema[GraphqlActions,Unit] = Schema(ObjectType("Query",tapFields))

} 
Example 16
Source File: VariablesInAllowedPosition.scala    From sangria   with Apache License 2.0 5 votes vote down vote up
package sangria.validation.rules


import sangria.schema.{InputType, Schema}
import sangria.ast
import sangria.ast.AstVisitorCommand
import sangria.marshalling.ToInput
import sangria.renderer.SchemaRenderer
import sangria.validation._

import scala.collection.mutable.{Map => MutableMap}


    def allowedVariableUsage(
      schema: Schema[_, _],
      varType: InputType[_],
      varDefaultValue: Option[ast.Value],
      locationType: InputType[_],
      locationDefaultValue: Option[(_, ToInput[_, _])]
    ) =
      if (!locationType.isOptional && varType.isOptional) {
        val hasNonNullVariableDefaultValue = varDefaultValue.exists(default => !default.isInstanceOf[ast.NullValue])
        val hasLocationDefaultValue = locationDefaultValue.isDefined

        if (!hasNonNullVariableDefaultValue && !hasLocationDefaultValue) false
        else TypeComparators.isSubType(schema, varType.nonOptionalType, locationType)
      } else TypeComparators.isSubType(schema, varType, locationType)
  }
} 
Example 17
Source File: TestExecutorHelper.scala    From naptime   with Apache License 2.0 5 votes vote down vote up
package org.coursera.naptime.ari.graphql.schema

import com.linkedin.data.DataMap
import org.coursera.naptime.ari.graphql.Models
import org.coursera.naptime.ari.graphql.SangriaGraphQlContext
import org.coursera.naptime.ari.graphql.SangriaGraphQlSchemaBuilder
import org.coursera.naptime.ari.graphql.marshaller.NaptimeMarshaller._
import org.coursera.naptime.ari.graphql.models.RecordWithUnionTypes
import org.coursera.naptime.ari.graphql.models.MergedCourse
import org.coursera.naptime.ari.graphql.models.MergedInstructor
import org.coursera.naptime.ari.graphql.models.MergedPartner
import org.coursera.naptime.ari.graphql.resolvers.NaptimeResolver
import play.api.libs.json.JsObject
import sangria.execution.Executor
import sangria.parser.QueryParser
import sangria.schema.Schema

import scala.concurrent.Await
import scala.concurrent.ExecutionContext
import scala.concurrent.ExecutionContext.Implicits.global
import scala.concurrent.duration.Duration

class TestExecutorHelper {

  def executeQuery(
      queryString: String,
      resourceData: Map[String, Map[String, List[DataMap]]]): JsObject = {
    val schemaTypes = Map(
      "org.coursera.naptime.ari.graphql.models.MergedCourse" -> MergedCourse.SCHEMA,
      "org.coursera.naptime.ari.graphql.models.FakeModel" -> RecordWithUnionTypes.SCHEMA,
      "org.coursera.naptime.ari.graphql.models.MergedPartner" -> MergedPartner.SCHEMA,
      "org.coursera.naptime.ari.graphql.models.MergedInstructor" -> MergedInstructor.SCHEMA)
    val allResources =
      Set(
        Models.courseResource,
        Models.instructorResource,
        Models.partnersResource,
        Models.fakeModelResource)
    val builder = new SangriaGraphQlSchemaBuilder(allResources, schemaTypes)
    val schema = builder.generateSchema().data.asInstanceOf[Schema[SangriaGraphQlContext, Any]]

    val queryAst = QueryParser.parse(queryString).get

    val context = SangriaGraphQlContext(
      FakeFetcherApi(resourceData),
      null,
      ExecutionContext.global,
      debugMode = true)

    Await
      .result(
        Executor
          .execute(
            schema,
            queryAst,
            context,
            variables = JsObject(Map.empty[String, JsObject]),
            deferredResolver = new NaptimeResolver()),
        Duration.Inf)
      .asInstanceOf[JsObject]
  }

} 
Example 18
Source File: FilterTest.scala    From naptime   with Apache License 2.0 5 votes vote down vote up
package org.coursera.naptime.ari.graphql.controllers.filters

import org.coursera.naptime.ari.graphql.GraphqlSchemaProvider
import org.coursera.naptime.ari.graphql.Models
import org.coursera.naptime.ari.graphql.SangriaGraphQlContext
import org.coursera.naptime.ari.graphql.SangriaGraphQlSchemaBuilder
import org.coursera.naptime.ari.graphql.models.MergedCourse
import org.coursera.naptime.ari.graphql.models.MergedInstructor
import org.coursera.naptime.ari.graphql.models.MergedPartner
import org.mockito.Mockito.when
import org.scalatest.concurrent.IntegrationPatience
import org.scalatest.concurrent.ScalaFutures
import org.scalatest.junit.AssertionsForJUnit
import org.scalatest.mockito.MockitoSugar
import play.api.libs.json.Json
import play.api.test.FakeRequest
import sangria.parser.QueryParser
import sangria.schema.Schema

import scala.concurrent.Future

trait FilterTest
    extends AssertionsForJUnit
    with MockitoSugar
    with ScalaFutures
    with IntegrationPatience {

  val baseOutgoingQuery = OutgoingQuery(Json.obj(), None)

  def noopFilter(incomingQuery: IncomingQuery) = {
    Future.successful(baseOutgoingQuery)
  }

  def exceptionThrowingFilter(incomingQuery: IncomingQuery): Future[OutgoingQuery] = {
    assert(false, "This filter should not be run")
    Future.successful(baseOutgoingQuery)
  }

  val filter: Filter

  val defaultQuery =
    """
      |query {
      |  __schema {
      |    queryType {
      |      name
      |    }
      |  }
      |}
    """.stripMargin

  val graphqlSchemaProvider = mock[GraphqlSchemaProvider]

  val allResources = Set(Models.courseResource, Models.instructorResource, Models.partnersResource)

  val schemaTypes = Map(
    "org.coursera.naptime.ari.graphql.models.MergedCourse" -> MergedCourse.SCHEMA,
    "org.coursera.naptime.ari.graphql.models.MergedPartner" -> MergedPartner.SCHEMA,
    "org.coursera.naptime.ari.graphql.models.MergedInstructor" -> MergedInstructor.SCHEMA)
  val builder = new SangriaGraphQlSchemaBuilder(allResources, schemaTypes)

  val schema = builder.generateSchema().data.asInstanceOf[Schema[SangriaGraphQlContext, Any]]
  when(graphqlSchemaProvider.schema).thenReturn(schema)

  def generateIncomingQuery(query: String = defaultQuery) = {
    val document = QueryParser.parse(query).get
    val header = FakeRequest("POST", s"/graphql").withBody(query)
    val variables = Json.obj()
    val operation = None
    IncomingQuery(document, header, variables, operation, debugMode = false)
  }

  def run(incomingQuery: IncomingQuery): Future[OutgoingQuery] = {
    filter.apply(noopFilter)(incomingQuery)
  }

  def ensureNotPropagated(incomingQuery: IncomingQuery): Future[OutgoingQuery] = {
    filter.apply(exceptionThrowingFilter)(incomingQuery)
  }
} 
Example 19
Source File: SangriaGraphQlSchemaBuilder.scala    From naptime   with Apache License 2.0 5 votes vote down vote up
package org.coursera.naptime.ari.graphql

import com.linkedin.data.DataMap
import com.linkedin.data.schema.RecordDataSchema
import com.typesafe.scalalogging.StrictLogging
import org.coursera.naptime.ari.graphql.schema.NaptimeTopLevelResourceField
import org.coursera.naptime.ari.graphql.schema.SchemaErrors
import org.coursera.naptime.ari.graphql.schema.SchemaMetadata
import org.coursera.naptime.ari.graphql.schema.WithSchemaErrors
import org.coursera.naptime.schema.Resource
import sangria.schema.Context
import sangria.schema.Schema
import sangria.schema.Value
import sangria.schema.Field
import sangria.schema.ObjectType

class SangriaGraphQlSchemaBuilder(resources: Set[Resource], schemas: Map[String, RecordDataSchema])
    extends StrictLogging {

  val schemaMetadata = SchemaMetadata(resources, schemas)

  
  def generateSchema(): WithSchemaErrors[Schema[SangriaGraphQlContext, DataMap]] = {
    val topLevelResourceObjectsAndErrors = resources.map { resource =>
      val lookupTypeAndErrors =
        NaptimeTopLevelResourceField.generateLookupTypeForResource(resource, schemaMetadata)
      val fields = lookupTypeAndErrors.data.flatMap { resourceObject =>
        if (resourceObject.fields.nonEmpty) {
          Some(
            Field.apply[SangriaGraphQlContext, DataMap, DataMap, Any](
              NaptimeTopLevelResourceField.formatResourceTopLevelName(resource),
              resourceObject,
              resolve = (_: Context[SangriaGraphQlContext, DataMap]) => {
                Value(new DataMap())
              }))
        } else {
          None
        }
      }
      lookupTypeAndErrors.copy(data = fields)
    }

    val topLevelResourceObjects = topLevelResourceObjectsAndErrors.flatMap(_.data)
    val schemaErrors = topLevelResourceObjectsAndErrors.foldLeft(SchemaErrors.empty)(_ ++ _.errors)

    val dedupedResources = topLevelResourceObjects.groupBy(_.name).map(_._2.head).toList
    val rootObject = ObjectType[SangriaGraphQlContext, DataMap](
      name = "root",
      description = "Top-level accessor for Naptime resources",
      fields = dedupedResources)

    WithSchemaErrors(Schema(rootObject), schemaErrors)
  }
} 
Example 20
Source File: GraphQLSchemaSpec.scala    From daml   with Apache License 2.0 5 votes vote down vote up
// Copyright (c) 2020 Digital Asset (Switzerland) GmbH and/or its affiliates. All rights reserved.
// SPDX-License-Identifier: Apache-2.0

package com.daml.navigator.graphql

import org.scalatest.{Matchers, WordSpec}
import sangria.parser.QueryParser
import sangria.schema.SchemaChange.DescriptionChange
import sangria.schema.Schema

import scala.io.Source

class GraphQLSchemaSpec extends WordSpec with Matchers {
  "The rendered schema" should {
    "match the expected schema definition" in {
      val idl =
        Source.fromInputStream(getClass.getResourceAsStream("/schema.graphql"), "UTF-8").mkString
      val schema = Schema.buildFromAst(QueryParser.parse(idl).get)

      // Compare schemata but ignore description changes.
      val changes = schema
        .compare(new GraphQLSchema(Set()).QuerySchema)
        .filter(!_.isInstanceOf[DescriptionChange])

      if (changes.nonEmpty) {
        fail(
          s"Schema definition does not match:\n- ${changes.map(_.description).mkString("\n- ")}\n")
      }
    }
  }
}