Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Javascript circular dependency in GraphQL code

I am new to Javascript and don't know how to solve this problem. I am creating a GraphQL service to provide query to a database, I would like to define three type: Person, Company and Relationship

type Relation: {
  person: Person
  company: Company
}

type Person: {
  relationship: Relation
}

type Company: {
  relationship: Relation
}

As you can see, they are mutually depended, I will got Person and Company undefined, is there a way to resolve this?

database schema:

// -------------------- Object(company) --------------------
objectType = new GraphQLObjectType ({
  name: 'Object',
  description: 'Object could be a Company, FinancialOrg, Person or Product.',
  fields: {
    id: {
      type: new GraphQLNonNull(GraphQLString),
    },
    entity_type: {
      type: new GraphQLNonNull(GraphQLString),
      description: 'could be Company, FinancialOrg, Person or Product.'
    },
    entity_id: {
      type: new GraphQLNonNull(GraphQLInt),
    },
    parent_id: {
      type: GraphQLString,
    },
    name: {
      type: new GraphQLNonNull(GraphQLString),
    },
    normalized_name: {
      type: new GraphQLNonNull(GraphQLString),
    },
    permalink: {
      type: new GraphQLNonNull(GraphQLString),
    }
  },
  resolveType: function(object) {
    return dbHandler.findObjectById(object.id);
  }
})

// -------------------- Relationship --------------------
var relationshipType = new GraphQLObjectType({
  name: 'Relationship',
  description: 'Describe the relationship between a person and a object(Corporation, fund)',
  fields: {
    id: {
      type: new GraphQLNonNull(GraphQLInt),
    },
    relationship_id: {
      type: new GraphQLNonNull(GraphQLInt),
    },
    person_object_id: {
      type: new GraphQLNonNull(GraphQLString),
    },
    relationship_object_id: {
      type: new GraphQLNonNull(GraphQLString),
      description: 'A Corporation or a Fund',
    },
  }
});

// -------------------- Person Type --------------------
personType = new GraphQLObjectType ({
  name: 'Person',
  fields: {
    id: {
      type: new GraphQLNonNull(GraphQLInt),
    },
    object_id: {
      type: new GraphQLNonNull(GraphQLString),
    },
    first_name: {
      type: new GraphQLNonNull(GraphQLString),
    },
    last_name: {
      type: new GraphQLNonNull(GraphQLString),
    },
    birthplace: {
      type: GraphQLString
    },
    affiliation_name: {
      type: GraphQLString
    },
  },
});
like image 929
Yechen Avatar asked Feb 11 '26 15:02

Yechen


1 Answers

Normally you wouldn't define a special Relationship type. In GraphQL, relationships among types are defined in the types themselves.

As examples, within your personType, you can have a field called companies, which resolves to a list of companies (companyTypes) that person is part of. In your companyType, you could similarly define a field people that would resolve to a list of personTypes.

This would give you essentially a many-to-many relationship between the two types, which it sounds like is defined in your database.

A personType in this style might look like:

personType = new GraphQLObjectType ({
  name: 'Person',
  fields: () => ({
    id: {
      type: new GraphQLNonNull(GraphQLInt),
    },
    companies: {
      type: new GraphQLList(companyType),
      resolve: person => dbHandler.getAssociatedCompanies(person.id),
      },
    },
  }),
});

As for circular dependency issues, notice above that rather than using an object literal for fields, you can instead use a function which returns the object, which will not cause any problems (though your linter might complain).

I would definitely suggest reading through the GraphQL Types as well and making sure you've chosen appropriate types for your fields. Once you're comfortable enough you will definitely want to investigate GraphQLInterfaceType, which allows you to define common fields other types can implement. Ultimately it's probably a better route to define your types separately and have them implement an interface rather than having a generic objectType.

Also note that resolveType probably doesn't do what you think it does. From the GraphQL Types: "[resolveType is] a function to determine which type is actually used when the field is resolved." You see that on GraphQL types that can be composed of multiple types, like GraphQLInterfaceType and GraphQLUnionType.

The Star Wars example helped me wrap my head around this stuff.

like image 145
Eric Streeper Avatar answered Feb 13 '26 15:02

Eric Streeper



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!