Careeroza
applyDecorators
Combine Many Decorators into One
Admin routes often need the same 4–5 decorators. applyDecorators bundles them.
src/auth/auth.decorator.ts
import { applyDecorators, SetMetadata, UseGuards } from '@nestjs/common';
import { ApiBearerAuth, ApiForbiddenResponse, ApiUnauthorizedResponse } from '@nestjs/swagger';
import { JwtAuthGuard } from './jwt-auth.guard';
import { RolesGuard } from './roles.guard';
import { Role, ROLES_KEY } from './roles.decorator';
export function Auth(...roles: Role[]) {
return applyDecorators(
SetMetadata(ROLES_KEY, roles),
UseGuards(JwtAuthGuard, RolesGuard),
ApiBearerAuth(),
ApiUnauthorizedResponse({ description: 'Missing or invalid token' }),
ApiForbiddenResponse({ description: 'Insufficient role' }),
);
}
// before: 5 lines on every admin route. After:
// @Auth(Role.Admin)
// @Delete(':id') remove(...) {}Decorator Composition Underneath
Example
applyDecorators just returns one decorator that calls the others in order. Same idea with legacy method decorators:
const applied: string[] = [];
function Tag(label: string): MethodDecorator {
return (_t, key) => { applied.push(String(key) + ': ' + label); };
}
function applyDecorators(...decorators: MethodDecorator[]): MethodDecorator {
return (target, key, descriptor) => {
for (const d of decorators) d(target, key, descriptor);
};
}
const Auth = (...roles: string[]) =>
applyDecorators(Tag('roles=' + roles.join(',')), Tag('guards=JwtAuthGuard,RolesGuard'), Tag('swagger=bearer'));
class ProductsController {
@Auth('admin')
remove() {}
@Auth('admin', 'seller')
create() {}
}
console.log(applied.join('\n'));
console.log('decorated methods:', Object.getOwnPropertyNames(ProductsController.prototype).filter((m) => m !== 'constructor'));Output
remove: roles=admin remove: guards=JwtAuthGuard,RolesGuard remove: swagger=bearer create: roles=admin,seller create: guards=JwtAuthGuard,RolesGuard create: swagger=bearer decorated methods: [ 'remove', 'create' ]