Reflector helps you read metadata set by custom decorators in NestJS. Custom decorators let you add extra info to classes or methods simply.
0
0
Reflector and custom decorators in NestJS
Introduction
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.