0
0
NestJSframework~5 mins

Reflector and custom decorators in NestJS

Choose your learning style9 modes available
Introduction

Reflector helps you read metadata set by custom decorators in NestJS. Custom decorators let you add extra info to classes or methods simply.

You want to mark routes or controllers with special info like roles or permissions.
You need to check metadata inside guards or interceptors to control access.
You want to keep your code clean by separating metadata from logic.
You want to reuse metadata reading logic across different parts of your app.
Syntax
NestJS
import { SetMetadata } from '@nestjs/common';

export const MyDecorator = (value: any) => SetMetadata('myKey', value);

// Using Reflector in a guard or interceptor
import { Reflector } from '@nestjs/core';

constructor(private reflector: Reflector) {}

const data = this.reflector.get('myKey', context.getHandler());

SetMetadata creates a decorator that attaches data to routes or classes.

Reflector reads that data later, usually inside guards or interceptors.

Examples
This custom decorator adds a list of roles as metadata.
NestJS
import { SetMetadata } from '@nestjs/common';

export const Roles = (...roles: string[]) => SetMetadata('roles', roles);
Reflector reads the 'roles' metadata from the current route handler.
NestJS
import { Reflector } from '@nestjs/core';

constructor(private reflector: Reflector) {}

const roles = this.reflector.get<string[]>('roles', context.getHandler());
Sample Program

This example shows a custom @Roles decorator that sets roles metadata. The RolesGuard uses Reflector to read this metadata and check if the user has any required role before allowing access.

NestJS
import { Controller, Get, UseGuards, SetMetadata, CanActivate, ExecutionContext, Injectable } from '@nestjs/common';
import { Reflector } from '@nestjs/core';

// Custom decorator to set roles metadata
export const Roles = (...roles: string[]) => SetMetadata('roles', roles);

// Guard that uses Reflector to check roles
@Injectable()
class RolesGuard implements CanActivate {
  constructor(private reflector: Reflector) {}

  canActivate(context: ExecutionContext): boolean {
    const requiredRoles = this.reflector.get<string[]>('roles', context.getHandler());
    if (!requiredRoles) {
      return true; // no roles required
    }
    // For demo, pretend user roles come from request
    const request = context.switchToHttp().getRequest();
    const userRoles = request.user?.roles || [];
    return requiredRoles.some(role => userRoles.includes(role));
  }
}

@Controller('cats')
export class CatsController {
  @Get()
  @Roles('admin')
  @UseGuards(RolesGuard)
  findAll() {
    return 'This route is restricted to admins';
  }
}
OutputSuccess
Important Notes

Always inject Reflector via constructor to access metadata.

Metadata keys should be unique strings to avoid conflicts.

Custom decorators keep your code organized and reusable.

Summary

Reflector reads metadata set by custom decorators.

Custom decorators add extra info to routes or classes.

Use them together to control behavior like access or logging.