Skip to content

Instantly share code, notes, and snippets.

@reggi
Last active July 10, 2023 14:11
Show Gist options
  • Star 5 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save reggi/3d7db7693f2e4a327af59df61acb8a92 to your computer and use it in GitHub Desktop.
Save reggi/3d7db7693f2e4a327af59df61acb8a92 to your computer and use it in GitHub Desktop.
How do I have nested resolvers in nestjs / type-graphql?

I am trying to find a way that a resolver can essentially return another resolver using nest.js for creating Resolvers, and type-graphql to create object types.

Here's an example with the star-wars graphql api

{
  allVehicles(first: 1, last: 100) {
    vehicles {
      name
      id
      filmConnection(first: 1, last: 100) {
        films {
          title
          characterConnection(first: 1, last: 100) {
            characters {
              name
            }
          }
        }
      }
    }
  }
}

As you can see above the vehicles type returns a filmConnection which allows you to pass in arguments. In type-graphql, would this be apart of the @ObjectType would it be defined in the @Resolver? Or does it need to be defined in some other way?


Failed Attempts

I set up an example of a couple of nested objects.

Which should look something like this as a query:

Note there are no arguments to these types, that could be optional, but I'd like the resolvers to pass along parent information.

{
  human {
    head {
      eyes {
        color
      }
    }
    body {
      neck
    }
  }
}

Here are the @ObjectTypes

@ObjectType()
class Eyes {
    @Field(type => String)
    color: string
}

@ObjectType()
class Head {
    @Field(type => Eyes, { nullable: true })
    eyes?: Eyes
}

@ObjectType()
class Body {
    @Field(type => String)
    neck: string
}

@ObjectType()
class Human {
    @Field(type => String, { nullable: true })
    name: string

    @Field(type => Head, { nullable: true })
    head?: Head

    @Field(type => Body, { nullable: true })
    body?: Body
}

First Approach, multiple Resolvers

@Resolver(type => Human)
export class HumanResolver {

    @Query(type => Human)
    human(): Human {
        console.log('a')
        return { name: 'Greg' }
    }

}

@Resolver(type => Head)
export class HeadResovler {

    @Query(type => Head)
    head(): Head {
        console.log('B')
        return {}
    }

}

@Resolver(type => Body)
export class BodyResolver {

    @Query(type => Body)
    body(): Body {
        console.log('C')
        return { neck: '102' }
    }

}

@Resolver(type => Eyes)
export class EyesResolver {

    @Query(type => Eyes)
    eyes(): Eyes {
        console.log('d')
        return { color: 'brown' }
    }

}

First Approach, One Resolvers, using @ResolveProperty

Here's another way to do it possibly, with one top level resovler and the rest are properties.

@Resolver(type => Human)
export class BeingResolver {

    @Query(type => Human)
    human(): Human {
        console.log('a')
        return { name: 'Greg' }
    }

    @ResolveProperty(type => Head)
    head(): Head {
        console.log('b')
        return {}
    }

    @ResolveProperty(type => Body)
    body(): Body {
        console.log('c')
        return { neck: '102' }
    }

    @ResolveProperty(type => Eyes)
    eyes(): Eyes {
        console.log('d')
        return { color: 'brown' }
    }
}

The main issue I see here is that @ResolveProperty only goes one level deep.

@shriomtri
Copy link

shriomtri commented Aug 19, 2022

This is not working as expected.

getLevel3Property throws error. Does not take any argument but in resolved still requires it.

@heji-staizen
Copy link

Thanks @reggi , If only I had seen this much earlier, it could have saved me a lot of time.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment