Що таке глобальні провайдери?
Що таке глобальний провайдер
Глобальний провайдер (global provider) - це провайдер, який доступний у всьому застосунку NestJS, навіть якщо модуль, де він оголошений, не імпортовано явно в інші модулі.
Іншими словами: якщо ти зареєстрував провайдер як глобальний, тобі більше не потрібно вказувати
imports: [SomeModule]у кожному модулі - NestJS сам робить цей провайдер доступним усюди.
Приклад без глобального провайдера
// logger.service.ts
@Injectable()
export class LoggerService {
log(msg: string) {
console.log(`[LOG]: ${msg}`);
}
}
// logger.module.ts
@Module({
providers: [LoggerService],
exports: [LoggerService],
})
export class LoggerModule {}Щоб використати LoggerService в інших модулях,
нам доведеться імпортувати LoggerModule вручну в кожному місці:
@Module({
imports: [LoggerModule],
})
export class UsersModule {}Приклад із глобальним провайдером
Зробимо модуль глобальним, використовуючи декоратор @Global():
import { Global, Module } from '@nestjs/common';
import { LoggerService } from './logger.service';
@Global()
@Module({
providers: [LoggerService],
exports: [LoggerService],
})
export class LoggerModule {}Тепер LoggerService доступний у всіх модулях застосунку,
навіть якщо LoggerModule ніде не імпортований.
@Injectable()
export class UsersService {
constructor(private readonly logger: LoggerService) {}
findAll() {
this.logger.log('Fetching users...');
return ['John', 'Alex'];
}
}NestJS автоматично реєструє LoggerService у глобальному DI-контейнері,
тому він доступний у будь-якому місці без додаткових імпортів.
Як це працює всередині
- Кожен модуль у NestJS має власну область видимості (scope).
- Коли ти додаєш
@Global(), Nest реєструє провайдери модуля в кореневому контейнері. - Усі інші модулі "бачать" ці провайдери, навіть не імпортуючи модуль.
Де це корисно
Глобальні провайдери зазвичай використовуються для кросс-застосунковних сервісів, наприклад:
| Тип сервісу | Приклад |
|---|---|
| Авторизація | AuthService, JwtService, AuthGuard |
| Конфігурація | ConfigService з @nestjs/config |
| Логування | LoggerService |
| Робота з кешем | CacheService, RedisService |
| Події / сповіщення | EventBus, NotificationService |
Важливо: обережно з глобальністю
Хоча це зручно, зловживати глобальними провайдерами не варто.
Мінуси:
- важко відстежити, звідки приходить залежність;
- порушується інкапсуляція модулів;
- можливі конфлікти імен при великій кількості глобальних провайдерів;
- тестування ускладнюється (mock потрібно підмінювати глобально).
Краще:
- використовувати глобальні провайдери лише для інфраструктури (логер, конфіг, кеш);
- а бізнес-логіку лишати модульною.
Альтернатива: глобальна реєстрація без @Global()
Іноді можна зареєструвати глобальний провайдер програмно,
наприклад, у main.ts чи через Dynamic Module.
Приклад через app.useGlobalFilters(), app.useGlobalPipes(), app.useGlobalInterceptors()
const app = await NestFactory.create(AppModule);
app.useGlobalFilters(new HttpExceptionFilter());
app.useGlobalPipes(new ValidationPipe());
app.useGlobalInterceptors(new LoggingInterceptor());Ці елементи теж стають глобальними провайдерами,
але на рівні всього застосунку (без декоратора @Global()).
Приклад динамічного глобального модуля
@Global()
@Module({})
export class ConfigModule {
static forRoot(envFile: string): DynamicModule {
return {
module: ConfigModule,
providers: [
{
provide: 'CONFIG_PATH',
useValue: envFile,
},
ConfigService,
],
exports: [ConfigService],
};
}
}Тепер ConfigService глобально доступний усюди.
Підсумок
| Поняття | Опис |
|---|---|
| Глобальний провайдер | Провайдер, доступний у всіх модулях без явного імпорту |
| Створюється через | @Global() над модулем, або useGlobal*() при ініціалізації |
| Використовується для | Загальносистемних сервісів: логер, конфіг, автентифікація |
| Переваги | Спрощує архітектуру, менше імпортів |
| Недоліки | Приховані залежності, складніше тестувати, ризик конфліктів |
| Рекомендація | Роби глобальними лише інфраструктурні сервіси, а бізнес-логіку - модульною |
Коротка відповідь
Для співбесідиКоротка відповідь допоможе вам впевнено відповідати на цю тему під час співбесіди.