graphql-compose-mongoose icon indicating copy to clipboard operation
graphql-compose-mongoose copied to clipboard

How to use internal mechanisms for dynamic population/projection for custom resolver

Open tasoskakour opened this issue 4 years ago • 3 comments

Hello!

Let's suppose that we've got the below 2 resolvers:

{
   userById: UserTC.mongooseResolvers.findById(),
   userGetMe: UserTC.addResolver({
      name:"userGetMe",
      args: {},
      type: User,
      resolve: (_,__,context) => {
           const {auth} = context;
           const {myId} = auth;
           return User.findById(myId); 
      }, 
   }).getResolver("userGetMe").withMiddlewares([getMyAuthId])
}

As you can see both of the resolvers above eventually utilize findById of mongoose. The only difference is that userGetMe resolver does not take any arguments but returns the User with the id of the current authenticated user.

The solution above is ideal and not realistic. In reality I have to manually populate any nested fields in the User.findById(myId) call, based on the fields request inside the graphql query. So basically I need to write helper functions like what you've got here in order to achieve my result.

My question is, is there a clever way to overcome this? Is there a way for the userGetMe resolver to eventually use the UserTC.mongooseResolvers.findById() resolver to fetch the User fields correctly populated, projected etc?

tasoskakour avatar Apr 09 '21 11:04 tasoskakour

You can try to reuse findById:

schemaComposer.Query.addFields({
  ...requireMiddlewares([authMiddleware, permissionCustomerMiddleware], {
    me: SysUserTC.mongooseResolvers
      .findById({ lean: true })
      .setDescription("Current User's Profile")
      .removeArg("_id") // <=== remove arg _id
      .wrapResolve((next) => (rp) => {
        const { userId } = rp.context.request;
        rp.args._id = userId
        return next(rp);
      }),

    sysUserById: SysUserTC.mongooseResolvers.findById({ lean: true }),
  }),
})

yurtaev avatar Apr 09 '21 12:04 yurtaev

Thanks for the reply @yurtaev, it worked!

Quick question regarding the requireMiddlewares, why aren't you using withMiddlewares? Just personal preference?

tasoskakour avatar Apr 09 '21 12:04 tasoskakour

requireMiddlewares just helper

/**
 * Add middlewares to resolvers
 * https://graphql-compose.github.io/docs/api/Resolver.html#withmiddlewares
 */
export const requireMiddlewares = (
  middlewares: Array<ResolverMiddleware<unknown, GraphQLContext>> = [],
  resolvers: ObjMap<Resolver>,
): ObjMap<Resolver> => {
  Object.keys(resolvers).forEach((k) => {
    resolvers[k] = resolvers[k].withMiddlewares(middlewares)
  })
  return resolvers
}

yurtaev avatar Apr 09 '21 12:04 yurtaev