2

我们正在使用 graphql-java 构建一个 graphql 服务器,但在符合 Relay 规范时遇到了麻烦。根据 Relay 规范,所有节点都必须可以通过单个查询检索:node(id: ID). graphql-java 文档显示了对 Relay 节点接口的支持,但是实际实现这一点的文档相当稀少。我们遇到的确切问题是了解如何为节点查询生成通用查找?Relay Todo 示例:https ://github.com/graphql-java/todomvc-relay-java展示了一个非常简单的基于代码的方法,使用单个数据获取器,这里的示例永远不需要“读取”节点“类型”或将该请求委托给正确的 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()
}

假设我们必须连接一个数据提取器,如上面最后一行所示。然而,这是文档开始变得模糊的地方。以上是否符合继电器规范?我们将如何实现一个单节点 dataFetcher,它返回对任何单个节点的引用,而不管底层类型(用户、其他类型等)如何?

4

2 回答 2

0

模式中的 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;
                }
            }))
于 2021-05-05T19:44:53.213 回答
0

你是对的,你需要实现一个节点数据获取器,它将从节点 ID 返回一个节点。

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

构建此类 id 的一种简单方法是将对象类型和对象 id 连接起来。示例:“用户:4234”。

作为中继 graphql 服务器规范指定:

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

我们需要将节点 ID 编码/解码为 base 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`
      
    }
  }
}
于 2020-09-04T03:23:30.520 回答