Fullstack CourseLearn by building
Back to week 1

Topic

Decorators

Definition

A decorator is a function applied to a class, method, property, or parameter with an @ prefix that attaches metadata Nest reads at runtime to change how that target is treated.

In simpler words

Decorators are labels you stick on code — @Controller, @Get, @Injectable — that tell Nest what the labeled thing is for.

Nest is built almost entirely from decorator metadata: which class is a controller, which method handles which route, which parameter is public/role-gated. This repo defines its own decorators for auth.

After this you can

  • Classify a decorator as class-level, method-level, or parameter-level
  • Read @Public(), @Roles(...), and @CurrentUser() and know what each attaches
  • Explain SetMetadata vs createParamDecorator
  • Predict what happens if a decorator is left off a route

Kinds of decorators Nest uses

Definition

Nest decorators attach metadata at the class level (@Controller, @Injectable, @Module), the method level (@Get, @Post, @Roles), or the parameter level (@Body, @Param, @CurrentUser), and Nest inspects that metadata when handling a request.

In simpler words

Class decorators say what the class is; method decorators say what a route does; parameter decorators say what to hand a method argument.

A class decorator like @Controller("tickets") or @Injectable() marks the whole class’s role in the DI/routing system.

A method decorator like @Get(":id") or @Roles("admin") attaches route or access metadata to one handler.

A parameter decorator like @Param("id") or @CurrentUser() tells Nest how to extract a value from the request and pass it as that argument.

All three kinds on one controller

@Controller('tickets')          // class decorator
export class TicketsController {
  @Delete(':id')                // method decorator
  @Roles('admin')               // method decorator (custom)
  remove(@Param('id') id: string) {  // parameter decorator
    return this.ticketsService.remove(id);
  }
}

Three decorator kinds, three different jobs, all metadata Nest reads before your method body runs.

This repo’s custom auth decorators

Definition

A custom decorator can be built from SetMetadata to attach arbitrary route metadata, or from createParamDecorator to compute and return a value from the current ExecutionContext.

In simpler words

@Public() and @Roles(...) just stick a metadata flag on a route; @CurrentUser() reaches into the request and hands back the logged-in user.

apps/api/src/common/auth/auth.decorators.ts defines Public = () => SetMetadata(IS_PUBLIC_KEY, true) and Roles = (...roles) => SetMetadata(ROLES_KEY, roles) — both are metadata flags that guards later read with a Reflector.

CurrentUser is built with createParamDecorator: it reads req.user (attached by the JWT strategy after a guard authenticates the request) and returns it directly as a typed User parameter.

Decorator definitions (apps/api)

export const Public = () => SetMetadata(IS_PUBLIC_KEY, true);
export const Roles = (...roles: Array<'admin' | 'member'>) =>
  SetMetadata(ROLES_KEY, roles);

export const CurrentUser = createParamDecorator(
  (_data: unknown, ctx: ExecutionContext): User => {
    const request = ctx.switchToHttp().getRequest<{ user: User }>();
    return request.user;
  },
);

JwtAuthGuard/RolesGuard read IS_PUBLIC_KEY and ROLES_KEY with Reflector; CurrentUser just projects request.user.

Mistake: expecting @CurrentUser() on a public route

// Wrong — no guard ran, request.user was never set
@Public()
@Get('whoami')
me(@CurrentUser() user: User) { return user; } // undefined

// Right — protected route, guard populates request.user first
@Get('whoami')
me(@CurrentUser() user: User) { return user; }

@CurrentUser() only works after an auth guard has run and attached request.user — @Public() skips that guard.

Keep in mind

  • A decorator with no code reading its metadata does nothing — always check which guard/pipe/interceptor consumes it.
  • Prefer this repo’s existing decorators (@Public, @Roles, @CurrentUser) over re-deriving auth state manually in a controller.
  • Order matters for stacked method decorators in some cases (e.g. guards run in registration order) — keep it consistent with existing controllers.

Test

Check your understanding

At least 10 questions — mix of concept, syntax, practical, and logic. Score ≥ 80% (enforced by the API) to save progress.

Checking your session…

10 questions · concept 3 · syntax 2 · practical 3 · logic 2

Concept1. Which statement best defines Nest decorators?
Syntax2. Which code-level choice matches Nest decorators?
Practical3. A reviewer spots a bug related to Nest decorators. What is the right fix?
Logic4. Which reasoning correctly explains Nest decorators?
Concept5. Which boundary does correct use of Nest decorators preserve?
Practical6. What is the safest next step when applying Nest decorators?
Syntax7. Which implementation direction matches the rule for Nest decorators?
Logic8. Which consequence follows from applying Nest decorators correctly?
Concept9. Which claim about Nest decorators is true in this Nest + Postgres monorepo?
Practical10. Which team practice best demonstrates Nest decorators?