CodePark/ questions / Controllers & routing
START PRACTICINGPRACTICE
Backend question · NestJS › Controllers & routing

How do you create a custom @CurrentUser() parameter decorator, and why is it better than reading req.user in every handler?

export const CurrentUser = createParamDecorator(
  (data: string | undefined, ctx: ExecutionContext) => {
    const user = ctx.switchToHttp().getRequest().user;
    return data ? user?.[data] : user;
  },
);

@Get("me")
me(@CurrentUser() user: UserPayload, @CurrentUser("id") id: string) {}

Create it with createParamDecorator(). It reads the user in one place, so handlers don't each need the raw request.

How it works. createParamDecorator() takes a factory function. The factory receives two things:

  • data: the argument passed to the decorator, for example a property name
  • the ExecutionContext

Whatever the factory returns becomes the handler's parameter. Here it reads req.user, which the auth guard set earlier. It can return a single property if data names one.

Why it is better than @Req() in every handler:

  • Handlers declare exactly what they need.
  • Handlers don't depend on platform types like the Express request.
  • Handlers are easier to unit test: you just pass a user object.
  • The logic lives in one place. You can extend it for other contexts, for example reading the user from GqlExecutionContext in GraphQL resolvers.

Custom param decorators also work with pipes. For example: @CurrentUser(new ValidationPipe({ validateCustomDecorators: true })).

  • Create it with createParamDecorator((data, ctx) => ...).
  • It reads req.user, which the auth guard set.
  • The data argument can select one property of the user.
  • Handlers avoid @Req(), so they are easier to test.
  • There is one place to adapt it for GraphQL or WebSockets.