nestjs / nest

A progressive Node.js framework for building efficient, scalable, and enterprise-grade server-side applications with TypeScript/JavaScript 🚀
https://nestjs.com
MIT License
67.69k stars 7.63k forks source link

Multi-Providers Support for Dependency Injection #14010

Closed vahidvdn closed 1 month ago

vahidvdn commented 1 month ago

Is there an existing issue that is already proposing this?

Is your feature request related to a problem? Please describe it

When you have multiple classes that implement the same interface. Let's say all of them has send() method. In order to call all of them, right now the only option in nestjs is:

export class AppService {
  constructor(
    private emailNotificationService: EmailNotificationService,
    private smsNotificationService: SMSNotificationService,
    private pushNotificationService: PushNotificationService,
  ) {}

  notifyAll() {
    this.emailNotificationService.send();
    this.smsNotificationService.send();
    this.pushNotificationService.send();
  }

Which is in contrast with open-close principle.

Describe the solution you'd like

The same thing exists in Angular:

export interface NotificationHandler {
  send(message: string): void;
}

@Injectable()
export class EmailNotificationService implements NotificationHandler {
  send(message: string): void {
    console.log(`Sending Email: ${message}`);
  }
}

@Injectable()
export class SMSNotificationService implements NotificationHandler {
  send(message: string): void {
    console.log(`Sending SMS: ${message}`);
  }
}

@Injectable()
export class PushNotificationService implements NotificationHandler {
  send(message: string): void {
    console.log(`Sending Push Notification: ${message}`);
  }
}

export const NotificationHandlers = new InjectionToken<NotificationHandler[]>('NotificationHandler');

@Component({
  selector: 'app-root',
  standalone: true,
  providers: [
    {
      provide: NotificationHandlers,
      useClass: EmailNotificationService,
      multi: true,
    },
    {
      provide: NotificationHandlers,
      useClass: SMSNotificationService,
      multi: true,
    },
    {
      provide: NotificationHandlers,
      useClass: PushNotificationService,
      multi: true,
    },
  ],
  template: `
  <button (click)="notifyAll('Hello from multi provider')">Notify all</button>
  `,
})
export class App {
  notificationHandlers: NotificationHandler[] = inject(NotificationHandlers);
  notifyAll(message: string): void {
    this.notificationHandlers.forEach((handler) => handler.send(message));
  }
}

Teachability, documentation, adoption, migration strategy

They can achieve this by passing an option like multi: true

What is the motivation / use case for changing the behavior?

To achieve better design for the open-close principle

micalevisk commented 1 month ago

duplicate #770

One way to achieve this: https://dev.to/micalevisk/nestjs-tip-multi-value-providers-almost-like-multi-from-angular-1c63