Основные концепции NestJS
Обзор
NestJS — это прогрессивный Node.js-фреймворк для создания эффективных, масштабируемых и поддерживаемых серверных приложений. Он построен на TypeScript и вдохновлён модульной архитектурой Angular. Фреймворк сочетает элементы объектно-ориентированного (OOP), функционального (FP) и реактивного функционального (FRP) программирования.
NestJS диктует чёткую архитектуру вокруг нескольких ключевых концепций: Modules, Controllers, Providers, Decorators, Dependency Injection, Middleware, Guards, Interceptors, Pipes и Exception Filters. Понимание каждой из них и порядка их выполнения в жизненном цикле запроса — основа грамотной работы с фреймворком.
1. Модули (Modules)
Модули — это базовые строительные блоки NestJS. Каждое приложение имеет как минимум один корневой модуль (AppModule), от которого Nest строит граф зависимостей приложения. Модуль — это класс с декоратором @Module(), который принимает четыре свойства
controllers— список контроллеров модуляproviders— сервисы, репозитории и другие провайдерыimports— другие модули, от которых зависит текущийexports— провайдеры, доступные другим модулям
Модули поддерживают также глобальный режим (@Global()) и динамическую конфигурацию (например, ConfigModule.forRoot()). Модульная архитектура обеспечивает разделение ответственностей, переиспользование кода и масштабируемость.
@Module({
controllers: [UsersController],
providers: [UsersService],
})
export class UsersModule {}2. Контроллеры (Controllers)
Контроллеры отвечают за обработку входящих HTTP-запросов и отправку ответов клиенту. Механизм маршрутизации определяет, какой контроллер обработает конкретный запрос. Контроллер — это класс с декоратором @Controller(), внутри которого методы помечаются декораторами HTTP-методов (@Get(), @Post(), @Put(), @Delete() и др.).
@Controller('users')
export class UsersController {
constructor(private usersService: UsersService) {}
@Get()
getUsers() {
return this.usersService.findAll();
}
}Контроллер принимает зависимости через механизм Dependency Injection (DI), не создавая их вручную.
3. Провайдеры (Providers)
Провайдеры — это классы, которые можно внедрить в другие компоненты через DI. К ним относятся:
- Сервисы (Services) — содержат бизнес-логику
- Репозитории (Repositories) — инкапсулируют работу с данными
- Фабрики (Factories) — создают объекты по условию
- Хелперы (Helpers) — вспомогательные утилиты
Провайдер помечается декоратором @Injectable(). Время жизни провайдеров по умолчанию совпадает со временем жизни всего приложения (singleton).
@Injectable()
export class UsersService {
findAll() {
return ['user1', 'user2', 'user3'];
}
}4. Dependency Injection (DI)
Внедрение зависимостей — одна из самых мощных возможностей NestJS. DI позволяет классам автоматически получать свои зависимости без ручного создания их экземпляров. Nest управляет контейнером DI: при запросе на создание класса он автоматически разрешает и инжектирует все необходимые зависимости.
DI в NestJS строится на принципе Inversion of Control (IoC): зависимости передаются извне, что делает код более тестируемым, гибким и слабосвязанным.
5. Декораторы (Decorators)
Декораторы — фундаментальный механизм NestJS для связывания классов и методов с метаданными. NestJS использует TypeScript-декораторы совместно с библиотекой reflect-metadata для хранения и чтения метаданных во время выполнения. Декораторы применяются на уровне классов, методов, свойств и параметров.
Основные встроенные декораторы:
@Module()— объявление модуля@Controller()— объявление контроллера@Injectable()— объявление провайдера@Get(),@Post()и др. — маршруты@Body(),@Param(),@Query()— извлечение данных запроса
NestJS также позволяет создавать кастомные декораторы для ролей, логирования, флагов функций и других сквозных задач.
6. Middleware (Посредники)
Middleware — это функции, выполняющиеся до обработчика маршрута. Они имеют доступ к объектам Request и Response, а также к функции next(). Middleware выполняются строго в порядке регистрации по принципу FIFO.
Типичные задачи Middleware:
- Логирование запросов
- Аутентификация и авторизация
- Трансформация данных запроса
- Обработка CORS, Helmet и других заголовков
Middleware могут быть глобальными (через app.use()) или применяться к конкретным маршрутам и модулям.
7. Guards (Стражи)
Guards определяют, будет ли обработан запрос, основываясь на условиях — например, проверке токена или роли пользователя. Guard возвращает true или false: при false Nest автоматически бросает ForbiddenException. Guards реализуют интерфейс CanActivate.
Guards идеально подходят для:
- Аутентификации (проверка JWT-токена)
- Авторизации (проверка ролей, прав доступа)
- Условного пропуска запроса
8. Interceptors (Перехватчики)
Interceptors вдохновлены паттерном Aspect-Oriented Programming (AOP) и позволяют добавлять логику до и после выполнения обработчика маршрута. Они имеют доступ к потоку выполнения через RxJS-операторы.
Основные применения Interceptors:
- Логирование запросов и ответов
- Кэширование (возврат кэшированного ответа)
- Трансформация ответа (оборачивание в стандартную структуру)
- Обработка ошибок (перехват и преобразование исключений)
9. Pipes (Конвейеры)
Pipes выполняют валидацию и трансформацию входных данных. Pipe применяется непосредственно перед вызовом обработчика маршрута и работает с аргументами, переданными этому обработчику. Если валидация не прошла — Pipe бросает исключение.
Встроенные pipes NestJS:
ValidationPipe— валидация DTO черезclass-validatorParseIntPipe,ParseUUIDPipe— преобразование типовDefaultValuePipe— подстановка значений по умолчанию
10. Exception Filters (Фильтры исключений)
Exception Filters перехватывают все необработанные исключения в приложении и формируют из них корректный HTTP-ответ. Фильтры можно применять глобально, на уровне контроллера или конкретного маршрута.
Основные применения:
- Стандартизация формата ошибок
- Логирование исключений
- Конвертация не-HTTP исключений в HTTP-ответы
Жизненный цикл запроса
Порядок выполнения компонентов при каждом входящем запросе строго определён:
| Этап | Компонент | Назначение |
|---|---|---|
| 1 | Middleware | Первичная обработка запроса (логирование, CORS) |
| 2 | Guards | Аутентификация и авторизация |
| 3 | Interceptors (до) | Логика перед обработчиком |
| 4 | Pipes | Валидация и трансформация данных |
| 5 | Route Handler | Основная бизнес-логика контроллера |
| 6 | Interceptors (после) | Логика после обработчика, трансформация ответа |
| — | Exception Filters | Перехват ошибок на любом этапе |
Понимание этого порядка критично для правильного размещения кода и предотвращения трудноуловимых багов.
Итоговая схема архитектуры
AppModule
├── Controllers → принимают HTTP-запросы
├── Providers → бизнес-логика, DI
└── Imports → другие модули
Запрос → Middleware → Guards → Interceptors → Pipes → Handler → Interceptors → Ответ
↕
Exception Filters
NestJS диктует “opinionated” (строго структурированный) подход к разработке: каждый элемент имеет чёткую роль, а соблюдение этих концепций обеспечивает создание тестируемых, масштабируемых и легко поддерживаемых приложений.