Discover how a few lines of code can save you hours of repetitive checks and bugs!
Why Reflector and custom decorators in NestJS? - Purpose & Use Cases
Imagine you have to check user permissions on every route manually by writing repetitive code inside each controller method.
You also want to add metadata to routes to control behavior, but you have to manage this metadata yourself everywhere.
Manually checking permissions and managing metadata leads to duplicated code, mistakes, and makes your app hard to maintain.
It's easy to forget checks or mix up metadata, causing bugs and security holes.
Using Reflector and custom decorators lets you attach metadata cleanly to routes or classes and read it easily in one place.
This keeps your code DRY, organized, and secure by centralizing permission checks and metadata handling.
if (user.role !== 'admin') { throw new ForbiddenException(); } // repeated in every method
@Roles('admin') // custom decorator
@UseGuards(RolesGuard) // guard uses Reflector to read metadataYou can build flexible, reusable, and clear access control and behavior rules across your app with minimal repeated code.
In a company app, you tag routes with roles like @Roles('manager') and the guard automatically blocks unauthorized users without extra code in each method.
Manual permission checks cause repeated, error-prone code.
Reflector reads metadata set by custom decorators to centralize logic.
This makes your app cleaner, safer, and easier to maintain.
Practice
Reflector class in NestJS when used with custom decorators?Solution
Step 1: Understand Reflector's role
The Reflector class is designed to read metadata that custom decorators attach to classes or methods.Step 2: Differentiate from other functions
It does not create decorators, change routing, or validate payloads; it only reads metadata.Final Answer:
To read metadata set by custom decorators on classes or methods -> Option AQuick Check:
Reflector reads metadata = D [OK]
- Thinking Reflector creates decorators
- Confusing Reflector with validation tools
- Assuming Reflector changes routing behavior
Solution
Step 1: Recall SetMetadata usage
SetMetadata is the NestJS helper to create decorators that attach metadata with a key and value.Step 2: Check each option
export const Roles = (roles: string[]) => SetMetadata('roles', roles); correctly returns SetMetadata with key 'roles' and the passed roles array. export function Roles(roles: string[]) { return Reflect.metadata('roles', roles); } uses Reflect.metadata which is not standard in NestJS. export const Roles = (roles: string[]) => Reflector.set('roles', roles); incorrectly calls Reflector.set which does not exist. export function Roles() { return SetMetadata('roles'); } calls SetMetadata without value, which is invalid.Final Answer:
export const Roles = (roles: string[]) => SetMetadata('roles', roles); -> Option DQuick Check:
SetMetadata creates decorators with key-value metadata = A [OK]
- Using Reflector to set metadata instead of reading
- Omitting the value argument in SetMetadata
- Using Reflect.metadata instead of SetMetadata
getData method?import { Controller, Get, UseGuards, SetMetadata } from '@nestjs/common';
import { Reflector } from '@nestjs/core';
const Roles = (roles: string[]) => SetMetadata('roles', roles);
@Controller('items')
export class ItemsController {
@Get()
@Roles(['admin'])
getData() {
return 'secret data';
}
}
// In a guard:
const reflector = new Reflector();
const roles = reflector.get<string[]>('roles', ItemsController.prototype.getData);
console.log(roles);Solution
Step 1: Understand metadata retrieval context
Reflector.get requires the target object and the property key (method name as string) to read metadata.Step 2: Analyze the call
The code calls reflector.get with ItemsController.prototype.getData as the second argument, which is a function, not the method name string 'getData'. This causes Reflector to fail to find metadata and return undefined.Final Answer:
undefined -> Option BQuick Check:
Reflector.get needs method name string, else returns undefined [OK]
- Passing method function instead of method name string
- Expecting metadata on class prototype instead of method
- Assuming metadata always returns array
import { SetMetadata } from '@nestjs/common';
function Permissions(permissions: string[]) {
return (target: any, key: string) => {
Reflect.defineMetadata('permissions', permissions, target, key);
};
}
class UserController {
@Permissions(['read'])
getUser() {
return 'user';
}
}Solution
Step 1: Check decorator implementation
The decorator manually calls Reflect.defineMetadata, which works but is not recommended in NestJS.Step 2: Use NestJS helper for consistency
SetMetadata is the standard NestJS helper that wraps Reflect.defineMetadata and ensures compatibility with Reflector and other NestJS internals.Final Answer:
The decorator should use SetMetadata instead of Reflect.defineMetadata -> Option CQuick Check:
Use SetMetadata for custom decorators in NestJS [OK]
- Using Reflect.defineMetadata directly instead of SetMetadata
- Ignoring NestJS decorator conventions
- Misunderstanding decorator parameters
@Roles decorator metadata. Which approach correctly uses Reflector and the custom decorator to achieve this?Solution
Step 1: Understand metadata inheritance
Roles can be set on method or class level. To get effective roles, use Reflector.getAllAndOverride which checks method first, then class.Step 2: Implement guard logic
Retrieve roles with getAllAndOverride, then compare with user's roles to allow or deny access.Final Answer:
Use Reflector.getAllAndOverride('roles', [context.getHandler(), context.getClass()]) to get roles, then check user roles against it -> Option AQuick Check:
getAllAndOverride merges metadata from method and class [OK]
- Ignoring class-level metadata roles
- Trying to set metadata inside guard
- Not using Reflector to read metadata
Ready to prove it?
Pass the test and this pattern moves unknown
