简体   繁体   中英

Deep query to nested types in GraphQL return NULL

Have a strange problem...

Query to nested types return null.

But, if I return anything in parent type - resolve return right result

My code:

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
                }
            }
        }
    })
 });

Query:

{
  admin {
    getAdmins {
      login
    } 
  }
}

Result:

{
  "data": {
    "admin": null
  }
}

If I changed returned value in fields admin in RootQuery:

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'#
                }
            }
        }
    })
 });

I've got expected result:

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

What is right solution for this issue? (without using dummy values in return)

Thank's a lot!

What you are seeing is the expected behavior. Imagine we have a User type with some fields:

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

And a way to fetch a single user:

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

If getUser returns an object representing a User , the resolvers for all the fields (ie id and name on the User type will be called.

When those fields (and whatever child fields they might have) resolve, you end up with a User object for the entire user field to return. A response might look something like:

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

Now, consider what happens when a user is not found and we return null instead. Our response looks like this:

"data": {
  "user": null
}

It doesn't make sense to call any of the resolvers for the User fields. Would you expect the API to still return an id or name in this case? If it did, what values would those fields have? If we just returned a null id and name , how would the client distinguish that object from a User that existed but really did have id and name null values?

The point is, if a field returns a GraphQLObjectType and it resolves to null, none of the resolvers on the GraphQLObjectType will be called.

By unnecessarily nesting your getAdmins field inside another GraphQLObjectType, you're forced to return some kind of object inside the resolver for admin . So you will need to either live with that, or avoid creating an AdminRootType altogether and just put the getAdmins field on your Query type directly, as per convention:

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

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM