Что такое decorator в NestJS?
Комментарии (1)
Ответ сгенерирован нейросетью и может содержать ошибки
Decorator в NestJS: полное объяснение
Decorator — это функция, которая добавляет метаданные и функциональность к классам, методам, параметрам и свойствам. Это основной механизм NestJS для определения маршрутов, middleware, зависимостей и др.
Что такое Decorator?
Decoratorы — это функции, которые начинаются с @ и описывают класс/метод/параметр. Они добавляют информацию о том, как этот класс/метод должен работать.
// Простой пример
@Controller('users')
export class UserController {
@Get(':id')
getUser(@Param('id') id: string) {
return { id };
}
}
Это эквивалентно Express коду:
app.get('/users/:id', (req, res) => {
res.send({ id: req.params.id });
});
Но в NestJS это четче, организованнее и типизировано.
Основные встроенные декораторы
1. Routing Decorators (маршрутизация)
@Controller('posts') // Префикс для всех маршрутов класса
export class PostController {
// GET /posts
@Get()
findAll() { }
// GET /posts/:id
@Get(':id')
findOne(@Param('id') id: string) { }
// POST /posts
@Post()
create(@Body() createPostDto: CreatePostDto) { }
// PUT /posts/:id
@Put(':id')
update(@Param('id') id: string, @Body() updatePostDto: UpdatePostDto) { }
// DELETE /posts/:id
@Delete(':id')
remove(@Param('id') id: string) { }
// PATCH /posts/:id
@Patch(':id')
patch(@Param('id') id: string, @Body() patchPostDto: PatchPostDto) { }
}
2. Параметр декораторы
@Get('/users/:id')
getUser(
@Param('id') id: string, // из URL
@Query('filter') filter: string, // из query string ?filter=...
@Body() body: UpdateDto, // из body
@Headers('x-token') token: string, // из заголовков
@Ip() ipAddress: string // IP адрес клиента
) {
// ...
}
// Для POST /users/{id}?filter=active
// URL: /users/123?filter=active
// Body: { name: 'John' }
// Headers: x-token: abc123
3. Dependency Injection Decorators
@Injectable()
export class UserService {
constructor(private db: DatabaseService) {}
// DatabaseService автоматически инъектится
}
@Controller('users')
export class UserController {
constructor(private userService: UserService) {}
// UserService автоматически инъектится
}
4. Module Decorators
@Module({
imports: [TypeOrmModule.forFeature([User])],
controllers: [UserController],
providers: [UserService],
exports: [UserService] // Экспортировать для других модулей
})
export class UserModule {}
Создание собственного декоратора
1. Простой декоратор для метода
// auth.decorator.ts
export const Auth = () => SetMetadata('auth', true);
// controller.ts
@Controller('admin')
export class AdminController {
@Get()
@Auth() // Добавляем метаданные
getAdminPanel() {
return 'Admin panel';
}
}
// guard.ts
@Injectable()
export class AuthGuard implements CanActivate {
canActivate(context: ExecutionContext): boolean {
const isProtected = Reflect.getMetadata('auth', context.getHandler());
if (!isProtected) return true;
const request = context.switchToHttp().getRequest();
return !!request.user; // Проверяем авторизацию
}
}
2. Декоратор с параметрами
export const HasRole = (role: string) => SetMetadata('role', role);
@Controller('users')
export class UserController {
@Get()
@HasRole('admin')
getUsers() { }
@Get()
@HasRole('moderator')
getModerationPanel() { }
}
3. Кастомный параметр декоратор
// user.decorator.ts
export const CurrentUser = createParamDecorator(
(data: unknown, ctx: ExecutionContext) => {
const request = ctx.switchToHttp().getRequest();
return request.user;
}
);
// controller.ts
@Get('profile')
getProfile(@CurrentUser() user: User) {
return user; // Автоматически извлекает текущего пользователя
}
4. Декоратор для класса
export const ValidateDto = () => {
return function <T extends { new (...args: any[]): {} }>(constructor: T) {
// Добавляем метаданные на класс
Reflect.defineMetadata('validate', true, constructor);
return constructor;
};
};
@ValidateDto()
export class CreateUserDto {
name: string;
email: string;
}
Практические примеры
1. Rate Limiting Decorator
export const RateLimit = (requests: number, windowMs: number) => {
return SetMetadata('rateLimit', { requests, windowMs });
};
@Controller('api')
export class ApiController {
@Get('/heavy-operation')
@RateLimit(5, 60000) // 5 запросов в минуту
heavyOperation() {
return 'result';
}
}
2. Логирование декоратор
export const Log = () => {
return MethodDecorator = (target, propertyKey, descriptor) => {
const originalMethod = descriptor.value;
descriptor.value = function (...args) {
console.log(`Calling ${propertyKey} with args:`, args);
const result = originalMethod.apply(this, args);
console.log(`${propertyKey} returned:`, result);
return result;
};
return descriptor;
};
};
@Controller('users')
export class UserController {
@Get()
@Log()
getUsers() { }
}
3. Трансформация данных
export const Transform = (transformer: (value: any) => any) => {
return SetMetadata('transformer', transformer);
};
@Get()
@Transform(data => data.toUpperCase())
getData() {
return 'hello';
}
// Вернёт 'HELLO'
Встроенные Guard/Pipe/Interceptor Decorators
import { UseGuards, UsePipes, UseInterceptors } from '@nestjs/common';
@Controller('admin')
@UseGuards(AuthGuard) // Применить Guard
@UsePipes(ValidationPipe) // Применить Pipe
@UseInterceptors(LoggingInterceptor) // Применить Interceptor
export class AdminController {
@Get()
getAdminPanel() { }
}
Порядок выполнения в NestJS
Request → Middleware → Guard → Interceptor (before) →
Pipe → Controller → Service →
Interceptor (after) → Exception Filters → Response
Декораторы определяют, какие Guard/Pipe/Interceptor применяются к методу.
Практический пример: полная аутентификация
// decorators/auth.decorator.ts
export const Auth = (roles?: string[]) => {
return applyDecorators(
SetMetadata('roles', roles || []),
UseGuards(AuthGuard),
ApiBearerAuth() // Документация
);
};
// controllers/admin.controller.ts
@Controller('admin')
export class AdminController {
@Get()
@Auth(['admin']) // Требует роли 'admin'
getAdminPanel() {
return 'Admin panel';
}
}
// guards/auth.guard.ts
@Injectable()
export class AuthGuard implements CanActivate {
constructor(private jwtService: JwtService) {}
canActivate(context: ExecutionContext): boolean {
const request = context.switchToHttp().getRequest();
const token = request.headers.authorization?.split(' ')[1];
if (!token) return false;
try {
request.user = this.jwtService.verify(token);
const requiredRoles = Reflect.getMetadata('roles', context.getHandler());
return requiredRoles.includes(request.user.role);
} catch {
return false;
}
}
}
Преимущества декораторов
✓ Декларативный код — чётко видно, что делает метод ✓ Переиспользуемость — один раз напиши, используй везде ✓ Разделение ответственности — логика и метаданные отделены ✓ Меньше boilerplate — вместо 10 строк кода один @Auth ✓ Типизация — всё типизировано ✓ Интеграция — легко интегрируется с NestJS системой
Вывод
Декораторы — это сердце NestJS. Они делают код чище, понятнее и более организованным. Встроенные декораторы (@Get, @Post, @Controller и т.д.) справляются с 90% задач. Для специальных задач создавай собственные декораторы, комбинируя SetMetadata, applyDecorators и Reflect API.