简体   繁体   English

带有Sangria的GraphQL架构

[英]GraphQL Schema with Sangria

I'm looking at the Sangria library for coding a GraphQL server in Scala. 我正在查看Sangria库,以便在Scala中编写GraphQL服务器。 It feels odd, however, that the same type system must be implemented twice: (1) as part of the GraphQL type declarations, and (2) also at the server side, as Scala case classes, with accompanying ObjectType, InterfaceType, etc. vals. 然而,奇怪的是,相同类型的系统必须实现两次:(1)作为GraphQL类型声明的一部分,(2)也在服务器端,作为Scala案例类,伴随ObjectType,InterfaceType等。瓦尔斯。

Hardcoding the type system in Scala is especially irksome, since my purpose is to be able to CRUD aggregates of arbitrary shape, where each shape is defined as a GraphQL collection of types. 在Scala中对类型系统进行硬编码尤其令人讨厌,因为我的目的是能够使用任意形状的CRUD聚合,其中每个形状被定义为GraphQL类型集合。 For example, say an instance of type Shape contains a GraphQL document as a field; 例如,假设Shape类型的实例包含GraphQL文档作为字段; and an instance of type Entity has a reference to its Shape and also contains a Json object of the shape defined in that Shape. 并且Entity类型的实例具有对其Shape的引用,并且还包含在该Shape中定义的形状的Json对象。

case class Shape(id: String, name: String, doc: sangria.ast.Document)
case class Entity(id: String, name: String, shape: Shape, content: JsValue)

For example, if the shape document is something like this: 例如,如果形状文档是这样的:

type Person {
  firstName: String!
  lastName: String!
  age: Int
}

then the Json content in the entity could be something like this: 那么实体中的Json内容可能是这样的:

{
  "firstName": "John",
  "lastName": "Smith",
  "age": 30
}

(A real example would, of course, also have nested types, etc.) (一个真实的例子当然也有嵌套类型等)

Thus, I seek to be able to define instances of type Entity whose shape is defined in their corresponding Shape. 因此,我试图能够定义Entity类型的实例,其形状在相应的Shape中定义。 I do NOT want to hardcode the corresponding sangria.schema.Schema but want to derive it directly from the shape document. 我不想硬编码相应的sangria.schema.Schema,但想直接从形状文档中派生它。

Is there a ready way to generate a GraphQL schema programmatically from a GraphQL document containing type declarations? 是否有一种现成的方法可以从包含类型声明的GraphQL文档以编程方式生成GraphQL模式?

For such dynamic use-cases, sangria provides a way to build a schema from GraphQL IDL. 对于这种动态用例,sangria提供了一种从GraphQL IDL构建模式的方法。 Here is how you can do it (I simplified your example a bit, but the same can be implemented when all this data comes from separate classes like Shape and Entity ): 这是你如何做到的(我简化了你的例子,但是当所有这些数据来自像ShapeEntity这样的单独的类时,同样可以实现):

import sangria.ast._
import sangria.schema._
import sangria.macros._
import sangria.marshalling.sprayJson._
import sangria.execution.Executor

import scala.concurrent.ExecutionContext.Implicits.global
import spray.json._

val schemaAst =
  gql"""
    type Person {
      firstName: String!
      lastName: String!
      age: Int
    }

    type Query {
      people: [Person!]
    }
  """

val schema = Schema.buildFromAst(schemaAst, builder)

val query =
  gql"""
    {
      people {
        firstName
        age
      }
    }
  """

val data =
  """
    {
      "people": [{
        "firstName": "John",
        "lastName": "Smith",
        "age": 30
      }]
    }
  """.parseJson

val result = Executor.execute(schema, query, data)

In order to define how resolve functions should be generated, you need to create a custom schema builder, like this one, and just override resolveField method: 为了定义如何生成resolve函数,您需要创建一个自定义模式构建器,就像这样,并且只需覆盖resolveField方法:

val builder =
  new DefaultAstSchemaBuilder[JsValue] {
    override def resolveField(typeDefinition: TypeDefinition, definition: FieldDefinition) =
      typeDefinition.name match {
        case "Query" ⇒
          c ⇒ c.ctx.asJsObject.fields get c.field.name map fromJson
        case _ ⇒
          c ⇒ fromJson(c.value.asInstanceOf[JsObject].fields(c.field.name))
      }

    def fromJson(v: JsValue) = v match {
      case JsArray(l) ⇒ l
      case JsString(s) ⇒ s
      case JsNumber(n) ⇒ n.intValue()
      case other ⇒ other
    }
  }

When you execute this example, you will see following JSON result : 执行此示例时,您将看到以下JSON result

{
  "data": {
    "people": [{
      "firstName": "John",
      "age": 30
    }]
  }
}

If you would like to see a more complex example, I would recommend you to check out GrapohQL Toolbox "proxy" . 如果您想查看更复杂的示例,我建议您查看GrapohQL Toolbox“proxy” This project takes it one step further and even adds custom directives to control the resolve function generation. 该项目更进了一步,甚至添加了自定义指令来控制解析函数的生成。 The code can be found here: 代码可以在这里找到:

https://github.com/OlegIlyenko/graphql-toolbox https://github.com/OlegIlyenko/graphql-toolbox

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM