node.jsgraphql

Graphql Error undefined adding a relationship


I have the following structure. Every Account can have one security type. So it's a one-to-many from SecurityType to Account. Everything works using the code

File: AccountSchema.js

const SecurityType = require('./LookupSchema').SecurityType;
console.log(Account);

const Account = new GraphQLObjectType({
    name: 'Account',
    description: 'Account access',
    fields: () =>
    ({
        id: {
            type: GraphQLString
        },
        security_type:
        {
            type: SecurityType,
            resolve(parent, args, ast){
                return new Promise((resolve, reject) => {

                    const db = ast.db;
                    const parameters = [parent.security_type_id];
                   db.query(db.connection, `SELECT * FROM lookups.security_type WHERE id = $1`, parameters)
                    .then(result =>
                    {
                        resolve(result.entrys.rows[0]);
                    })
                    .catch(err =>
                    {
                        reject(err.message);
                    });
                });
            }
        }
    })
});

module.exports = {
  Account : Account
}


File: LookupSchema.js

const Account = require('./AccountSchema').Account;
console.log(Account);


const SecurityType = new GraphQLObjectType({
    name: 'SecurityType',
    description: 'Used to for specifying security type',
    fields: () =>
    ({
        id: {
            type: GraphQLString
        }
    })
});

module.exports = {
    SecurityType: SecurityType
}


File: Query.js
const Query = new GraphQLObjectType({
    name: 'Query',
    description: 'Root query object',
    fields: () => ({
        accounts: {
            type: new GraphQLList(Account),
            resolve(root, args, ast) {

                return new Promise((resolve, reject) => {
                    const db = ast.db;
                    const parameters = [];
                    db.query(db.connection, `SELECT * FROM accounts.account`, parameters)
                    .then(result =>
                    {
                        console.log(result);
                        resolve(result.entrys.rows);
                    })
                    .catch(err =>
                    {
                        console.log(err);
                        reject(err.message);
                    });
                });

            }
        },
        securityTypes: {
            type: new GraphQLList(SecurityType),
            resolve(root){
                return new Promise((resolve, reject) => {
                    const db = ast.db;
                    const parameters = [];
                    db.query(db.connection, `SELECT * FROM lookups.security_type`, parameters)
                    .then(result =>
                    {
                        resolve(result.entrys.rows);
                    })
                    .catch(err =>
                    {
                        reject(err.message);
                    });
                });
            }
        }
    })
});

The problem I have is when I add to the file LookupSchema.js the accounts

const SecurityType = new GraphQLObjectType({
    name: 'SecurityType',
    description: 'Used to for specifying security type',
    fields: () =>
    ({
        id: {
            type: GraphQLString
        },
        accounts: {
            type: new GraphQLList(Account),
            resolve(parent, args, ast){
                return new Promise((resolve, reject) => {

                    const db = ast.db;
                    const parameters = [parent.id];
                   db.query(db.connection, `SELECT * FROM accounts.account WHERE security_type_id = $1`, parameters)
                    .then(result =>
                    {
                        resolve(result.entrys.rows);
                    })
                    .catch(err =>
                    {
                        reject(err.message);
                    });
                });
            }
        }
    })
}); 

I get the following error when I start the service

Error: Can only create List of a GraphQLType but got: undefined.

I put console.log for each Account and SecurityType to check for the import and I noticed in LookupSchema, Account is undefined. I did some research and this might be a circular issue but not quite sure a solution for it.


Solution

  • To avoide the Cyclic Problem you can use the require function inside the fields() function.

    So, Inside AccountSchema.js fields:() function will first import the SecurityType then only we will be using the the other fields with the return {}, same for other files.

    AccountSchema.js

    const {
        GraphQLObjectType,
        GraphQLString,
    } = require('graphql');
    
    const Account = new GraphQLObjectType({
        name: 'Account',
        description: 'Account access',
        fields: () => {
            const SecurityType = require('./LookUpSchema');
            return {
                id: {
                    type: GraphQLString,
                },
                security_type:
                {
                    type: SecurityType,
                    resolve(parent, args, ast) {
                        return new Promise((resolve, reject) => {
                            const db = ast.db;
                            const parameters = [parent.security_type_id];
                            db.query(db.connection, 'SELECT * FROM lookups.security_type WHERE id = $1', parameters)
                                .then((result) => {
                                    resolve(result.entrys.rows[0]);
                                })
                                .catch((err) => {
                                    reject(err.message);
                                });
                        });
                    },
                },
            };
        },
    
    });
    
    module.exports = Account;
    

    LookUpSchema.js

    const {
        GraphQLObjectType,
        GraphQLString,
        GraphQLList,
    } = require('graphql');
    
    const SecurityType = new GraphQLObjectType({
        name: 'SecurityType',
        description: 'Used to for specifying security type',
        fields: () => {
            const Account = require('./AccountSchema');
            return {
                id: {
                    type: GraphQLString,
                },
                accounts: {
                    type: new GraphQLList(Account),
                    resolve(parent, args, ast) {
                        return new Promise((resolve, reject) => {
                            const db = ast.db;
                            const parameters = [parent.id];
                            db.query(db.connection, 'SELECT * FROM accounts.account WHERE security_type_id = $1', parameters)
                                .then((result) => {
                                    resolve(result.entrys.rows);
                                })
                                .catch((err) => {
                                    reject(err.message);
                                });
                        });
                    },
                },
            };
        },
    });
    
    module.exports = SecurityType;
    

    Query.js

    const {
        GraphQLList,
        GraphQLObjectType,
        GraphQLSchema,
    } = require('graphql');
    
    const Account = require('./AccountSchema');
    const SecurityType = require('./LookUpSchema');
    
    console.log('Account', Account);
    
    const Query = new GraphQLObjectType({
        name: 'Query',
        description: 'Root query object',
        fields: () => ({
            accounts: {
                type: new GraphQLList(Account),
                resolve(root, args, ast) {
                    return new Promise((resolve, reject) => {
                        const db = ast.db;
                        const parameters = [];
                        db.query(db.connection, 'SELECT * FROM accounts.account', parameters)
                            .then((result) => {
                                console.log(result);
                                resolve(result.entrys.rows);
                            })
                            .catch((err) => {
                                console.log(err);
                                reject(err.message);
                            });
                    });
                },
            },
            securityTypes: {
                type: new GraphQLList(SecurityType),
                resolve(root) {
                    return new Promise((resolve, reject) => {
                        const db = ast.db;
                        const parameters = [];
                        db.query(db.connection, 'SELECT * FROM lookups.security_type', parameters)
                            .then((result) => {
                                resolve(result.entrys.rows);
                            })
                            .catch((err) => {
                                reject(err.message);
                            });
                    });
                },
            },
        }),
    });
    
    
    const schema = new GraphQLSchema({
        query: Query,
       // mutation: MutationType,
    });
    
    module.exports = schema;
    

    GraphiQL

    enter image description here