0

I reformulated the question and answered it here: My graphql resolvers have a circular dependency

I am trying to create circular dependency in ApolloGraphQL. The problem is that I can't figure out how to solve the circular references on the resolver side. The use case looks like this:

type Episode {

  Id: String

  ParentSeason: Season // I don't have this right now (circular dependency)

  // etc... A pretty complex type
}



type Season {

  Id: String

  EpisodeList: [Episode]

  // etc... A pretty complex type
}

The way I built this is by creating an Entity(simple class) from the database records and then I added an asGqType() function that adds the additional resolvers to the "raw" object. (I also have a REST API that's why)

The SeasonEntity looks like this:

class SeasonEntity {

  constructor(seasonDBRecord) {
      this.Id = seasonDBRecord.id;
      etc...
  }
  
  asGqType = () => {
    return {
      ...this,
      EpisodeList: () => {
          const episodeEntities = await episodeRepository.getEpisodes(); // returns EpisodeEntity[]
          return episodeEntities.map(episode => episode.asGqType() );
      }
      etc etc...
    }
 }

It looks really nice, you just call asGqType() and you don't have to deal with the child complexities.

But the problem appears when I try to extend the EpisodeEntity.asGqType() with ParentSeason as it would rely on SeasonEntity which already relies on EpisodeEntity. So javascript will never resolve this: it's normal, I agree.

How could I change this so that my entities can reference any other entity and be referenced by any other entity? I am not looking for a "quick fix" as I have a lot of complex entities. I've seen some people talking about GraphQLObjectType but I am not sure how to actually use that.

I am grateful for any advice, even on how to rearchitect all this. Thank you for your time!

2
  • GraphQL allows for circular references in type definitions. Commented Nov 24, 2022 at 17:34
  • @MichelFloyd yes it does, but how can I leverage that and not bring too much complexity into my code(resolver)? Commented Nov 25, 2022 at 11:10

1 Answer 1

1

You're dealing with a one-to-many relationship between Season and Episode. This should be straightforward.

Your schema:

type Season {
  id: ID!
  name: String!
  episodes: [Episode!]
}

type Episode: {
  id: ID!
  name: String!
  number: Number!
  season: Season!
}

Let's assume these types map to two different tables in a relational database. The resolver for episodes should then be something like:

season: {
  episodes: ({ id }) => 
    episodeRepository.getEpisodes({ seasonId: id }) // depends on your ORM
}

And your resolver for an episode's season should be:

episode: {
  season: ({ seasonId }) => seasonRepository.getSeason({ id: seasonId }) 
}

You don't have to await a resolver (unless you need to get some intermediate results), Apollo server will handle that for you.

I'm not sure about your ORM so can't be specific about the syntax of those two queries. The first one means: return episodes for which the seasonId has the id of the season I'm resolving. The second one means return the season for which the id is equal to the seasonId (foreign key) of the episode I'm resolving.

Sign up to request clarification or add additional context in comments.

10 Comments

But this way, the episodeRepository.getEpisodes returns only raw data from the database. It doesn't return an episode with the season resolver function.
I don't get it how you leverage the resolver for the episode, when you create other types that reference an episode
1) Yes, getEpisodes only returns raw data from the db. That resolves the episodes field. 2) If you have other types that resolve to episodes that also have a foreign key into the episodes table you can use the same pattern as with seasons. 3) Your types are not complex by a long shot. These are straightforward GraphQL patterns. Read my full blog series to cover more relational <-> GraphQL cases.
Yes and? You won't usually need to replicate many of those, only the one that decides how to find the root object. Resolvers that compute values based on the other fields of an object can remain unchanged.
You're going to need to create a repo with a minimal reproducible example. In any case it's not a GraphQL issue or constraint, more of an issue with how you're implementing your class structure.
|

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.