GraphQL Schema with Sangria
我正在查看用于在 Scala 中编写 GraphQL 服务器的 Sangria 库。然而,奇怪的是,同一个类型系统必须实现两次:(1)作为 GraphQL 类型声明的一部分,(2)也在服务器端,作为 Scala 案例类,伴随着 ObjectType、InterfaceType 等。 vals.
在 Scala 中对类型系统进行硬编码尤其令人讨厌,因为我的目的是能够对任意形状的聚合进行 CRUD,其中每个形状都被定义为 GraphQL 类型的集合。例如,假设 Shape 类型的实例包含一个 GraphQL 文档作为字段;并且 Entity 类型的实例具有对其 S??hape 的引用,并且还包含该 Shape.
中定义的形状的 Json 对象
1
2 |
例如,如果形状文档是这样的:
1
2 3 4 5 |
那么实体中的Json内容可能是这样的:
1
2 3 4 5 |
{
“firstName”:“John”, “lastName”:“Smith”, “age”: 30 } |
(一个真实的例子当然也有嵌套类型等)
因此,我寻求能够定义实体类型的实例,其形状在其相应的形状中定义。我不想硬编码相应的 sangria.schema.Schema 但想直接从形状文档中派生它。
有没有现成的方法可以从包含类型声明的 GraphQL 文档中以编程方式生成 GraphQL 模式?
- 为什么如此痛苦,例如,将 sangria.ast.Type 映射到 sangria.schema.OutputType?
对于此类动态用例,sangria 提供了一种从 GraphQL IDL 构建模式的方法。这是你可以做到的(我稍微简化了你的例子,但是当所有这些数据来自像 Shape 和 Entity 这样的单独类时,同样可以实现):
1
2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 |
import sangria.ast._
import sangria.schema._ import sangria.macros._ import sangria.marshalling.sprayJson._ import sangria.execution.Executor import scala.concurrent.ExecutionContext.Implicits.global val schemaAst = type Query { val schema = Schema.buildFromAst(schemaAst, builder) val query = val data = val result = Executor.execute(schema, query, data) |
为了定义应该如何生成 resolve 函数,您需要创建一个自定义模式构建器,就像这个一样,并且只需覆盖 resolveField 方法:
1
2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 |
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 { |
当你执行这个例子时,你会看到下面的 JSON result:
1
2 3 4 5 6 7 8 |
{
“data”: { “people”: [{ “firstName”:“John”, “age”: 30 }] } } |
如果您想查看更复杂的示例,我建议您查看 GraphohQL Toolbox “proxy”。该项目更进一步,甚至添加了自定义指令来控制解析函数的生成。代码可以在这里找到:
https://github.com/OlegIlyenko/graphql-toolbox
- 非常感谢,天师!这可能正是我正在寻找的。
- 不过有一个问题。如果 c.field.fieldType 是 OutputType[Int] 类型,则 JsNumber 的情况应返回 Int,如果 OutputType[Long] 等,则返回 Long。不幸的是,我们只得到 OutputType[_],TypeTag 已擦除(因此无法比较 typeOf [T] 与 =:= 或者)。这使得编写正确的 fromJson 函数变得非常麻烦,因为它不仅必须考虑 ScalarLongType,还必须考虑 OptionType(ScalarLongType),以及枚举和联合类型等。不过,这是一个小问题,可能希望在未来版本的桑格利亚汽酒中得到解决。
- @silverberry 类型信息在运行时也可用。这是一个可以根据类型信息提取正确 scala 类型的函数示例:github.com/OlegIlyenko/graphql-toolbox/blob/master/app/…
来源:https://www.codenong.com/43665937/