Що таке провайдери і як працює впровадження залежностей у NestJS?
Провайдери та впровадження залежностей у NestJS
Провайдери є основною концепцією в NestJS. Сервіси, репозиторії, фабрики, хелпери — все, що декороване @Injectable(), може бути провайдером. IoC контейнер NestJS автоматично управляє їхньою інстанціацією та впровадженням.
Сервіси (Найпоширеніший провайдер)
typescript
// users/users.service.ts
import { Injectable, NotFoundException } from '@nestjs/common';
@Injectable()
export class UsersService {
private users = [
{ id: 1, name: 'Alice' },
{ id: 2, name: 'Bob' },
];
findAll() {
return this.users;
}
findOne(id: number) {
const user = this.users.find(u => u.id === id);
if (!user) throw new NotFoundException(`Користувача #${id} не знайдено`);
return user;
}
create(data: { name: string }) {
const user = { id: Date.now(), ...data };
this.users.push(user);
return user;
}
}Впровадження сервісу в контролер
typescript
@Controller('users')
export class UsersController {
// NestJS автоматично впроваджує UsersService через конструктор
constructor(private readonly usersService: UsersService) {}
@Get()
findAll() {
return this.usersService.findAll();
}
}NestJS читає тип TypeScript UsersService і вирішує його з реєстру провайдерів модуля.
Сфери провайдерів
typescript
import { Injectable, Scope } from '@nestjs/common';
@Injectable({ scope: Scope.DEFAULT }) // Синглтон (за замовчуванням) — один екземпляр
@Injectable({ scope: Scope.REQUEST }) // Новий екземпляр на запит
@Injectable({ scope: Scope.TRANSIENT }) // Новий екземпляр на впровадження
export class UsersService {}Користувацькі провайдери
useValue — Впровадження константи
typescript
@Module({
providers: [
{ provide: 'API_KEY', useValue: 'my-secret-key' },
],
})
export class AppModule {}
// Впровадження з @Inject()
@Injectable()
export class ApiService {
constructor(@Inject('API_KEY') private apiKey: string) {}
}useClass — Переопределення з іншим класом
typescript
@Module({
providers: [
{ provide: LoggerService, useClass: MockLoggerService },
],
})useFactory — Динамічний провайдер
typescript
@Module({
providers: [
{
provide: 'DATABASE',
useFactory: async (config: ConfigService) => {
return await createDatabaseConnection(config.get('DB_URL'));
},
inject: [ConfigService],
},
],
})useExisting — Псевдонім провайдера
typescript
{ provide: 'LoggerAlias', useExisting: LoggerService }Впровадження між сервісами
typescript
@Injectable()
export class PostsService {
constructor(
private readonly usersService: UsersService, // автоматично впроваджений
private readonly emailService: EmailService,
) {}
async createPost(userId: number, data: CreatePostDto) {
const user = await this.usersService.findOne(userId);
await this.emailService.sendNotification(user.email);
// ...
}
}Підсумок
Контейнер DI NestJS працює за рахунок:
- Сканування класів
@Injectable(), зареєстрованих у провайдері модуля - Читання типів параметрів конструктора (рефлексія TypeScript)
- Вирішення та впровадження правильних екземплярів
Це забезпечує слабке зв'язування, легке модульне тестування (мок-впровадження) та управління життєвим циклом (синглтони, запитово-скоповані тощо).
Коротка відповідь
Для співбесідиPremium
Коротка відповідь допоможе вам впевнено відповідати на цю тему під час співбесіди.