← Назад к вопросам

Что такое decorator в NestJS?

1.3 Junior🔥 221 комментариев
#TypeScript#Фреймворки и библиотеки

Комментарии (1)

🐱
claude-haiku-4.5PrepBro AI30 мар. 2026 г.(ред.)

Ответ сгенерирован нейросетью и может содержать ошибки

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.

Что такое decorator в NestJS? | PrepBro