对 GraphQL 中嵌套类型的深度查询返回 NULL

Posted

技术标签:

【中文标题】对 GraphQL 中嵌套类型的深度查询返回 NULL【英文标题】:Deep query to nested types in GraphQL return NULL 【发布时间】:2019-07-05 04:06:02 【问题描述】:

有一个奇怪的问题...

对嵌套类型的查询返回 null。

但是,如果我返回父类型中的任何内容 - 解析返回正确的结果

我的代码:

import  GraphQLList, GraphQLString, GraphQLID, GraphQLObjectType, GraphQLSchema  from 'graphql';
import AdminModel from '../models/Admin.model';

const AdminType = new GraphQLObjectType(
    name: 'AdminType',
    fields: 
        _id:  type: GraphQLID ,
        login:  type: GraphQLString ,
        password:  type: GraphQLString 
    
);

const AdminRooteType = new GraphQLObjectType(
    name: 'AdminRooteType',
    fields: 
        getAdmins: 
            type: new GraphQLList(AdminType),
            resolve() 
                return AdminModel.find()
            
        
    
)

export default new GraphQLSchema( 
    query: new GraphQLObjectType(
        name: 'RootQuery',
        fields: 
            admin: 
                type: AdminRooteType,
                resolve() 
                   // EMPTY RESOLVE - EMPTY RESULT
                
            
        
    )
 );

查询:


  admin 
    getAdmins 
      login
     
  

结果:


  "data": 
    "admin": null
  

如果我在 RootQuery 的 admin 字段中更改了返回值:

import  GraphQLList, GraphQLString, GraphQLID, GraphQLObjectType, GraphQLSchema  from 'graphql';
import AdminModel from '../models/Admin.model';

const AdminType = new GraphQLObjectType(
    name: 'AdminType',
    fields: 
        _id:  type: GraphQLID ,
        login:  type: GraphQLString ,
        password:  type: GraphQLString 
    
);

const AdminRooteType = new GraphQLObjectType(
    name: 'AdminRooteType',
    fields: 
        getAdmins: 
            type: new GraphQLList(AdminType),
            resolve() 
                return AdminModel.find()
            
        
    
)

export default new GraphQLSchema( 
    query: new GraphQLObjectType(
        name: 'RootQuery',
        fields: 
            admin: 
                type: AdminRooteType,
                #resolve() #
                    #// RETURN ANYTHING HERE:#
                  #  return 'foobar'#
                
            
        
    )
 );

我得到了预期的结果:


  "data": 
    "admin": 
      "getAdmins": [
        
          "login": "123"
        ,
        
          "login": "12asdf3"
        
      ]
    
  

这个问题的正确解决方案是什么? (不使用虚拟值作为回报)

非常感谢!

【问题讨论】:

【参考方案1】:

您看到的是预期的行为。想象一下,我们有一个带有一些字段的 User 类型:

const UserType = new GraphQLObjectType(
  name: 'User',
  fields: 
    id:  type: GraphQLID ,
    name:  type: GraphQLString ,
  
)

还有一种获取单个用户的方法:

const QueryType = new GraphQLObjectType(
  name: 'Query',
  fields: 
    user: 
      type: AdminRooteType,
      resolve: () => getUser(),
    ,
  ,
)

如果getUser 返回一个表示User 的对象,则将调用所有字段的解析器(即User 类型上的idname

当这些字段(以及它们可能拥有的任何子字段)解析时,您最终会得到一个用户对象,以便整个 user 字段返回。响应可能类似于:

"data": 
  "user": 
    "id": 1,
    "name": "Maria",
    "comments": [
      
        "id": 1,
        // and so on...
      
    ]
  

现在,考虑当找不到用户而我们返回 null 时会发生什么。我们的响应如下所示:

"data": 
  "user": null

为 User 字段调用任何解析器是没有意义的。在这种情况下,您是否希望 API 仍返回 idname?如果是这样,这些字段将具有什么值?如果我们只返回一个空的idname,客户端如何将该对象与存在但确实具有idname 空值的用户区分开来?

关键是,如果一个字段返回一个 GraphQLObjectType 并且它解析为 null,则不会调用 GraphQLObjectType 上的任何解析器。

通过将 getAdmins 字段不必要地嵌套在另一个 GraphQLObjectType 中,您不得不在 admin 的解析器中返回某种对象。因此,您需要忍受这种情况,或者完全避免创建AdminRootType,而只需按照约定将getAdmins 字段直接放在您的查询类型上:

const QueryType = new GraphQLObjectType(
  name: 'Query',
  fields: 
    getAdmins: 
      type: new GraphQLList(AdminType),
      resolve: () => AdminModel.find(),
    ,
  ,
)

【讨论】:

非常感谢,丹尼尔!主要思想是按类型(管理员、文章、订阅者等)对我的查询和突变进行分组。我认为这是让我的结构更清晰

以上是关于对 GraphQL 中嵌套类型的深度查询返回 NULL的主要内容,如果未能解决你的问题,请参考以下文章

为啥我的 graphql 嵌套查询返回 null?

如何处理 GraphQL 中的嵌套输入

GraphQL 简单嵌套查询返回空字段

GraphQL 嵌套查询返回 null

为什么无法在graphql中过滤深层嵌套查询?

Absinthe Graphql 嵌套查询安全性