首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >带Sangria的GraphQL模式

带Sangria的GraphQL模式
EN

Stack Overflow用户
提问于 2017-04-27 18:59:01
回答 1查看 2.2K关注 0票数 6

我正在查看Sangria库,以便在Scala中编写GraphQL服务器。但是,奇怪的是,同一类型的系统必须实现两次:(1)作为GraphQL类型声明的一部分,(2)在服务器端,作为Scala case类,附带ObjectType、InterfaceType等vals。

在Scala中对类型系统进行硬编码特别令人厌烦,因为我的目的是能够创建任意形状的聚集,其中每个形状都定义为类型的GraphQL集合。例如,假设类型形状的实例包含作为字段的GraphQL文档;类型实体的实例具有对其形状的引用,并且还包含在该形状中定义的形状的Json对象。

代码语言:javascript
复制
case class Shape(id: String, name: String, doc: sangria.ast.Document)
case class Entity(id: String, name: String, shape: Shape, content: JsValue)

例如,如果形状文档如下所示:

代码语言:javascript
复制
type Person {
  firstName: String!
  lastName: String!
  age: Int
}

那么实体中的Json内容可以是这样的:

代码语言:javascript
复制
{
  "firstName": "John",
  "lastName": "Smith",
  "age": 30
}

(一个实际的例子当然也有嵌套类型,等等)

因此,我寻求能够定义类型实体的实例,其形状是在其相应的形状中定义的。我不想硬编码相应的sangria.schema.Schema,而是想直接从shape文档派生它。

是否有现成的方法可以从包含类型声明的GraphQL文档中以编程方式生成GraphQL模式?

EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2017-05-01 15:03:13

对于这种动态用例,sangria提供了一种从GraphQL IDL构建模式的方法。下面是如何做到这一点(我稍微简化了示例,但当所有这些数据都来自ShapeEntity这样的独立类时,同样的方法也可以实现):

代码语言:javascript
复制
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)

为了定义应该如何生成resolve函数,您需要创建一个自定义模式构建器,就像这个构造器一样,只需覆盖resolveField方法:

代码语言:javascript
复制
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
    }
  }

执行此示例时,您将看到以下JSON result

代码语言:javascript
复制
{
  "data": {
    "people": [{
      "firstName": "John",
      "age": 30
    }]
  }
}

如果您希望看到一个更复杂的示例,我建议您查看GrapohQL工具箱“代理”。该项目更进一步,甚至添加了自定义指令来控制解析函数的生成。代码可以在这里找到:

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

票数 5
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/43665937

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档