使用graphql-java构建中继GraphQL服务器

问题描述

我们正在使用graphql-java来构建graphql服务器,并且无法遵守Relay规范。根据中继规范,必须通过单个查询node(id: ID)可检索所有节点。 graphql-java文档显示了对Relay节点接口的支持,但是实际实现此功能的文档很少。我们遇到的确切问题是了解如何为节点查询生成通用查询? Relay Todo示例:https://github.com/graphql-java/todomvc-relay-java显示了使用单个datafetcher的极其简单的基于代码的方法,此处的示例无需“读取”节点“类型”或将请求委托给正确的dataFetcher。

schema.graphqls:

type Query {
    node(id: ID!): Node
    user(id: ID!): User
    otherType(id:ID!): OtherType
}

interface Node {
   id: ID!
}

type User implements Node {
   id: ID!
   firstName: String
   lastName: String
}

type OtherType implements Node {
   id: ID!
   description: String
   stuff: String
}

我们当前正在使用SDL生成我们的模式(如下所示)

@Bean
private GraphQLSchema schema() {
     Url url = Resources.getResource("schema.graphqls");
     String sdl = Resources.toString(url,Charsets.UTF_8);
     GraphQLSchema graphQLSchema = buildSchema(sdl);
     this.graphQL = GraphQL.newGraphQL(graphQLSchema).build();
     return graphQLSchema;
}
private GraphQLSchema buildSchema(String sdl) {
      TypeDefinitionRegistry typeRegistry - new SchemaParser().parse(sdl);
      RuntimeWiring runtimeWiring = buildWiring();
      SchemaGenerator schemaGenerator = new SchemaGenerator();
      return schemaGenerator.makeExecutableSchema(typeRegistry,runtimeWiring);
}
private RuntimeWiring buildWiring(){
    return RuntimeWiring.newRuntimeWiring()
    .type(newTypeWiring("Query")
          .dataFetcher("user",userDispatcher.getUserById()))
    .type(newTypeWiring("Query")
          .dataFetcher("otherType",otherTypeDispatcher.getOtherTypeById()))
    .type(newTypeWiring("Query")
          .dataFetcher("node",/*How do we implement this data fetcher? */))
    .build()
}

大概,我们必须连接数据提取器,如上面的最后一行所示。但是,这是文档开始变得朦胧的地方。以上是否符合中继规范?

无论基础类型(用户,OtherType等)如何,我们将如何实现单节点dataFetcher,该数据返回对任何单个节点的引用?

解决方法

是的,您需要实现一个节点数据提取程序,该数据提取程序将从Node ID中返回一个Node。

我将假设您正在使用基础sql数据库:Node可以是任何类型,这意味着您不能将数据库ID用作Node ID(因为两个不同类型的节点可能具有相同的数据库ID )。您需要构建自己的Node ID。

构建此类ID的一种简单方法是将对象类型和对象ID串联在一起。例如:“ User:4234”。

根据中继graphql服务器规范指定:

我们得到的ID是base64字符串。 ID设计为不透明 (唯一应传递给节点上id参数的是 查询系统中某个对象的id的结果不变,并且 base64字符串是GraphQL中有用的约定,用于提醒查看者 该字符串是一个不透明的标识符。

我们需要将节点ID编码/解码为以64为底。

下面的代码尚未经过测试,但是可以使您了解如何进行操作。

DataFetcher dataFetcher = new DataFetcher() {
            
  @Override
  Object get(DataFetchingEnvironment environment) {
    Object argument = environment.getArgument("id");
    if(argument instanceof String) {
      String node = (String) argument;
      //TODO decode base 64 nodeId
      //TODO split nodeId into String `nodeType` and Long `id`
      //TODO retrieve your object of type `nodeType` and id `id`
      
    }
  }
}
,

架构中的 Node 接口需要 TypeResolver 和 Data Fetcher 实现。

即使你提供了一个数据获取器实现并按照 AllirionX 的建议将其连接起来,你仍然需要为 Node 接口提供一个解析器来帮助 graphql-java 理解它应该解析哪个具体的对象类型。

.type(newTypeWiring("Query").dataFetcher("node",new NodeDataFetcher()))

类似这样的 -

.type(newTypeWiring("Node").typeResolver(new TypeResolver() {
                @Override
                public GraphQLObjectType getType(TypeResolutionEnvironment env) {
                    return null;
                }
            }))

相关问答

错误1:Request method ‘DELETE‘ not supported 错误还原:...
错误1:启动docker镜像时报错:Error response from daemon:...
错误1:private field ‘xxx‘ is never assigned 按Alt...
报错如下,通过源不能下载,最后警告pip需升级版本 Requirem...