#Custom Decorator undefined on other GraphQL resolvers

1 messages · Page 1 of 1 (latest)

real geyser
#

I have a Custom Decorator that returns user details created from the an AuthGuard.

auth.guard.ts

import {
  Injectable,
  CanActivate,
  ExecutionContext,
  UnauthorizedException,
} from '@nestjs/common'
import { GqlExecutionContext } from '@nestjs/graphql'
import { JwtService } from '@nestjs/jwt'

@Injectable()
export class AuthGuard implements CanActivate {
  constructor(private jwtService: JwtService) {}

  async canActivate(context: ExecutionContext): Promise<boolean> {
    const ctx = GqlExecutionContext.create(context).getContext()
    if (!ctx.headers.authorization) {
      return false
    }
    ctx.user = await this.validateToken(ctx.headers.authorization)
    return true
  }

  async validateToken(auth: string) {
    if (auth.split(' ')[0] !== 'Bearer') {
      throw new UnauthorizedException('Invalid access token')
    }
    const token = auth.split(' ')[1]

    try {
      const decoded = await this.jwtService.verifyAsync(token)
      return decoded
    } catch (err) {
      const message = 'Token error: ' + (err.message || err.name)
      throw new UnauthorizedException(message)
    }
  }
}

custom.decorator.ts

import { createParamDecorator, ExecutionContext } from '@nestjs/common'
import { GqlExecutionContext } from '@nestjs/graphql'

export const CustomDecorator = createParamDecorator(
  (_data, context: ExecutionContext) => {
    const ctx = GqlExecutionContext.create(context).getContext()
    return ctx.user
  },
)

export default CustomDecorator

But the custom decorator returns undefined on some GraphQL resolvers files, with basically within the same module and auth guards.

#

Works in post.resolver.ts

@Resolver('Post')
@UseGuards(AuthGuard)
export class PostResolver {
  @Query('posts')
  async find(@CustomDecorator() customDecorator: any): Promise<IPost[]> {
    console.log('customDecorator => posts', customDecorator) // working
    returns []
  }
}

Not working in comment.resolver.ts

@Resolver('Comment')
@UseGuards(AuthGuard)
export class CommentResolver {
  @Query('comments')
  async find(@CustomDecorator() customDecorator: any): Promise<IComment[]> {
    console.log('customDecorator => comments', customDecorator) // not working, undefined
    return []
  }
}
upper lance
#

@real geyser - What is wrong with just using the context itself, which is best practice and less work for the server 🙂 ?

@Resolver('Post')
@UseGuards(AuthGuard)
export class PostResolver {
  @Query('posts')
  async find(@Context() context: Context): Promise<IPost[]> {
    console.log('user => posts', context.user) // working
    returns []
  }
}
real geyser
#

Hi @upper lance, the @Context decorator is from @nestjs/graphql right? Tried it, but still undefined though

upper lance
#

What is undefined @real geyser ? The context itself? Or the user is missing? Did you assign the context in your GraphQLModule.forRoot call? This is what my context option looks like using Fastify.

context: (request: FastifyRequest, reply: FastifyReply) => ({ req: request, res: reply }),
#

Hmm.. I just noticed the docs suggest what you are doing. Should work too, but I'd say injecting Context is the norm.

#

A CurrentUser decorator is more explicit, but again, injecting and using the context is also a GraphQL norm. 🤷🏻‍♂️

#

And as you can see, you are missing req on your context object too in your decorator definition.

real geyser
boreal frost
#

So what's the difference between the posts resolver and the comments resolver?

real geyser
boreal frost
#

Does @Context() work on both? I think I saw you say it comes in as undefined still, right?

real geyser
boreal frost
#

Okay, that leads me to think that the guard isn't running the same way on both

real geyser
# boreal frost Okay, that leads me to think that the guard isn't running the same way on both

when I console.log the context in the auth guard, it returns the same context. btw, here's how my modules looks, if it helps, custom module is one of the many modules in the app.module.ts

custom.module.ts

import { Module } from '@nestjs/common'
import { JwtModule } from '@nestjs/jwt'

import { PostResolver } from './post/post.resolver'
import { AuthResolver } from './auth/auth.resolver'
import { CommentResolver } from './comment/comment.resolver'
import { DateScalar } from '~/scalars/date.scalar'
import { PostService } from '~/services/post/post.sevice'
import { AuthService } from '~/services/auth/auth.service'
import { CommentService } from '~/services/comment/comment.service'
import { PrismaService } from '~/services/prisma.service'

@Module({
  imports: [
    JwtModule.register({
      secret: process.env.JWT_SECRET ?? 'secret-123',
      signOptions: {
        expiresIn: '7d',
      },
    }),
  ],
  providers: [
    PostResolver,
    AuthResolver,
    CommentResolver,
    DateScalar,
    PostService,
    AuthService,
    CommentService,
    PrismaService,
  ],
})
export class CustomModule {}