preloader
學習

Fix Nodejs Graphql Circular Import

Fix Nodejs Graphql Circular Import

Circular import components are common within nodejs and graphql. This article provide a easy way to resolve that warning. The easy solution is adding related imports to limited scope in javascript instead of importing them at file start position.

The example scenario contains three parts: User, Role and UserRoleRel. An user has many roles and a role has many user had been taken. The relationship of many-to-many is recorded at UserRoleRel

Below are excerpt solution code about nodejs with graphql:

User model:

// User.js
const graphql = require("graphql");
const joinMonster = require("join-monster");

const User = new graphql.GraphQLObjectType({
  name: "User",
  /* 
     skip
     ...
     ...
     ...
  */
  // excerpt code
  fields: () => {
    const { Role } = require("./Role"); // <== critical import within fields scope

    return {
      id: {
        type: graphql.GraphQLID,
        extensions: {
          joinMonster: {
            sqlColumn: "id",
          },
        },
      },
      name: {
        type: graphql.GraphQLString,
        extensions: {
          joinMonster: {
            sqlColumn: "name",
          },
        },
      },
      roles: {
        type: new graphql.GraphQLList(Role), // because here use "Role" the imported
        description: "some roles",
        joinMonster: {
          junction: {
            sqlTable: "user_role_rel",
            sqlJoins: [
              (userTable, userRoleRelTable) =>
                `${userTable}.id = ${userRoleRelTable}.uid`,
              (userRoleRelTable, roleTable) =>
                `${userRoleRelTable}.rid = ${roleTable}.id`,
            ],
          },
        },
      },
      /*
       * skip
       * ...
       * ...
       * ...
       */
    };
  },
});

module.exports = {
  User,
};

 

Role model:

// Role.js
const graphql = require("graphql");
const joinMonster = require("join-monster");

const Role = graphql.GraphQLObjectType({
  name: "Role",
  /*
   * skip
   * ...
   * ...
   * ...
   */
  // excerpt code
  fields: () => {
    const { User } = require("./User"); // <== critical import within fields scope

    return {
      id: {
        type: graphql.GraphQLID,
        extensions: {
          joinMonster: {
            sqlColumn: "id",
          },
        },
      },
      name: {
        type: graphql.GraphQLString,
        extensions: {
          joinMonster: {
            sqlColumn: "name",
          },
        },
      },
      users: {
        type: new graphql.GraphQLList(User), // // because here use "User" the imported
        description: "some users",
        extensions: {
          joinMonster: {
            junction: {
              sqlTable: "user_role_rel",
              sqlJoins: [
                (roleTable, userRoleRelTable) =>
                  `${roleTable}.id = ${userRoleRelTable}.rid`,
                (userRoleRelTable, userTable) =>
                  `${userRoleRelTable}.uid = ${userTable}.id`,
              ],
            },
          },
        },
      },
      /*
       * skip
       * ...
       * ...
       * ...
       */
    };
  },
});
module.exports = {
  Role,
};

 

UserRoleRel is a table in concept that has columns such as uid for refering id within table user and rid for id within table role. So I won’t go through detail.

Reference link: