Що таке провайдер (provider)?
Провайдер (Provider) в NestJS - це будь-який клас, який можна впровадити (інжектувати) в інші класи через систему Dependency Injection (DI). Простіше кажучи, провайдер - це те, що надає якийсь функціонал чи дані, і може використовуватися іншими компонентами (контролерами, сервісами, гвардами, пайпами тощо).
Основна ідея
Провайдер - це об'єкт, який створюється й керується NestJS. Nest сам вирішує:
- коли створити екземпляр провайдера;
- як впровадити його в потрібні класи;
- скільки копій має існувати (за замовчуванням - singleton, тобто один спільний екземпляр).
Простий приклад провайдера
import { Injectable } from '@nestjs/common';
@Injectable()
export class UsersService {
private users = [{ id: 1, name: 'John' }];
findAll() {
return this.users;
}
}Цей UsersService - провайдер, тому що він позначений декоратором @Injectable().
Його можна впровадити в контролер чи інший сервіс:
import { Controller, Get } from '@nestjs/common';
import { UsersService } from './users.service';
@Controller('users')
export class UsersController {
constructor(private readonly usersService: UsersService) {}
@Get()
getUsers() {
return this.usersService.findAll();
}
}Як NestJS створює й впроваджує провайдери
- Кожен провайдер реєструється в
@Module()(у секціїproviders). - NestJS поміщає всі провайдери в DI-контейнер (IoC контейнер).
- Коли інший клас вказує залежність у конструкторі, NestJS автоматично знаходить і впроваджує потрібний екземпляр.
Типи провайдерів
| Тип провайдера | Приклад | Опис |
|---|---|---|
| Клас-провайдер | @Injectable() class UsersService {} | Найпоширеніший тип |
| Значення (value) провайдер | { provide: 'CONFIG', useValue: { port: 3000 } } | Повертає просте значення чи об'єкт |
| Фабрика (factory) провайдер | { provide: 'TOKEN', useFactory: () => new Date() } | Створює значення динамічно через функцію |
| Псевдонім (alias) провайдер | { provide: 'Alias', useExisting: UsersService } | Робить посилання на вже наявний провайдер |
| Користувацький клас-провайдер | { provide: 'Logger', useClass: CustomLogger } | Дозволяє підмінити реалізацію класу |
Приклади різних провайдерів
useValue
@Module({
providers: [
{ provide: 'API_KEY', useValue: '12345' },
],
})
export class AppModule {}Ін'єкція:
@Injectable()
export class SomeService {
constructor(@Inject('API_KEY') private apiKey: string) {}
}useFactory
@Module({
providers: [
{
provide: 'RANDOM_NUMBER',
useFactory: () => Math.random(),
},
],
})
export class AppModule {}useClass
@Injectable()
class DefaultLogger {
log(msg: string) {
console.log('[Default]', msg);
}
}
@Injectable()
class CustomLogger {
log(msg: string) {
console.log('[Custom]', msg);
}
}
@Module({
providers: [
{ provide: DefaultLogger, useClass: CustomLogger },
],
})
export class AppModule {}Тепер усюди, де запитується DefaultLogger, буде використовуватися CustomLogger.
Провайдери та скоуп (Scope)
За замовчуванням провайдер - singleton, але можна змінити область його дії:
@Injectable({ scope: Scope.REQUEST })
export class RequestScopedService {
// створюється заново на кожен HTTP-запит
}| Scope | Опис |
|---|---|
| Default (Singleton) | Один екземпляр на весь застосунок |
| Request | Новий екземпляр для кожного запиту |
| Transient | Новий екземпляр для кожного використання |
Де реєструються провайдери
Зазвичай - всередині модуля:
@Module({
providers: [UsersService],
exports: [UsersService],
})
export class UsersModule {}Щоб використати UsersService в іншому модулі:
@Module({
imports: [UsersModule],
})
export class AuthModule {}Підсумок
| Поняття | Опис |
|---|---|
| Провайдер | Клас чи значення, кероване DI контейнером NestJS |
| Призначення | Постачати функціонал, логіку чи дані іншим частинам застосунку |
| Основний інструмент | @Injectable() і система Dependency Injection |
| Реєструється | У секції providers модуля |
| Типи | useClass, useValue, useFactory, useExisting |
Коротка відповідь
Для співбесідиКоротка відповідь допоможе вам впевнено відповідати на цю тему під час співбесіди.