Search code examples
javascriptgraphqlgraphql-jsexpress-graphql

Many to Many graphql schema error


I'm new with GrpahQL and I'm trying to simulate Many to Many relationship between Users and Groups. I have the followinf types defined in my schema:

// UserType.js
const {
    GraphQLObjectType,
    GraphQLString,
    GraphQLList,
    GraphQLID } = require('graphql');

const {
    GraphQLEmail } = require('graphql-custom-types');

const GroupType = require('./GroupType'); const AuthService = require('../../services/AuthService');

let authService = new AuthService();

const UserType = new GraphQLObjectType({
    name: "UserType",
    fields: () => ({
        id: { type: GraphQLID },
        user: { type: GraphQLString },
        password: { type: GraphQLString },
        name: { type: GraphQLString },
        lastname: { type: GraphQLString },
        email: { type: GraphQLEmail },
        groups: {
            type: new GraphQLList(GroupType),
            resolve(parentValue) {
                return authService.userGroups(userId);
            }
        }
    }) });


module.exports = UserType;

and this is the other file:

// GroupType.js
const {
    GraphQLObjectType,
    GraphQLString,
    GraphQLID,
    GraphQLList
} = require('graphql');

const UserType = require('./UserType');
const AuthService = require('../../services/AuthService');

let authService = new AuthService();


const GroupType = new GraphQLObjectType({
    name: "GroupType",
    fields: () => ({
        id: { type: GraphQLID },
        name: { type: GraphQLString },
        description: { type: GraphQLString },
        users: {
            type: new GraphQLList(UserType),
            resolve(parentArgs) {
                return authService.userGroups(parentArgs.id);
            }
        }
    })
});

module.exports = GroupType;

This example doesn't work for me because for some reason i got this error:

Error: Can only create List of a GraphQLType but got: [object Object].

This error happens only for the GroupType and not for the UserType when both are similars. What's going on here? What am I doing wrong?


Solution

  • The problem is that UserType requires GroupType, and GroupType requires UserType: this is known as a circular dependency.

    What happens is that UserType.js gets required, exports an {} while finishing to run (this is standard Node.js module execution), requires GroupType, which requires back UserType and gets an empty object back, and exports the correct GraphQL GroupType to UserType. So UserType works because it is a list of GroupType, but GroupType doesn't it got an empty object for its require of UserType.

    To circumvent this, you can use a runtime require in GroupType.js:

    // GroupType.js
    ...
    
    // Remove the line which requires UserType at the top
    // const UserType = require('./UserType');
    const AuthService = require('../../services/AuthService');
    
    ...
    
    const GroupType = new GraphQLObjectType({
        ...
        fields: () => ({
            ...
            users: {
                type: new GraphQLList(require('./UserType')), // Require UserType at runtime
                ...
            }
        })
    });
    
    ...