Injection de dépendances

Dependency Injection (NestJS)

La Dependency Injection (DI) est un principe fondamental de NestJS.
Elle permet d’injecter automatiquement des dépendances (ex. services, repositories) dans d’autres classes (ex. contrôleurs) sans les instancier manuellement avec new.

L’objectif est de :

  • séparer les responsabilités,
  • faciliter les tests,
  • réduire le couplage entre les classes,
  • centraliser la gestion des dépendances dans les modules.

Injection de dépendance dans un module

Étape 1 : décorer le service avec @Injectable()

Un service doit être injectable pour pouvoir être utilisé ailleurs.

import { Injectable } from '@nestjs/common';

@Injectable()
export class UsersService {
  findAll() {
    return ['user1', 'user2'];
  }
}

@Injectable() indique à NestJS que cette classe peut être gérée par le système d’injection de dépendance.

Étape 2 : déclarer le service dans les providers du module
import { Module } from '@nestjs/common';
import { UsersController } from './users.controller';
import { UsersService } from './users.service';

@Module({
  controllers: [UsersController],
  providers: [UsersService],  // important
})
export class UsersModule {}

Sans l’ajouter dans providers, NestJS ne pourra pas l’injecter.

Étape 3 : injecter le service dans le contrôleur
Copier le code
import { Controller, Get } from '@nestjs/common';
import { UsersService } from './users.service';

@Controller('users')
export class UsersController {
  constructor(private usersService: UsersService) {}

  @Get()
  getUsers() {
    return this.usersService.findAll();
  }
}

Ce qui se passe : NestJS voit que UsersController a besoin de UsersService

  • Il cherche UsersService dans les providers
  • Il crée une instance et l’injecte automatiquement

On n’écrit jamais :

Copier le code
this.usersService = new UsersService(); 

Injection de dépendance entre modules

Lorsque l’on veut utiliser un service d’un module dans un autre module, il faut l’exporter.

Exemple : AuthModule qui utilise UsersService

UsersModule

@Module({
  controllers: [UsersController],
  providers: [UsersService],
  exports: [UsersService], // permet de l’utiliser ailleurs
})
export class UsersModule {}

AuthModule

import { Module } from '@nestjs/common';
import { AuthService } from './auth.service';
import { UsersModule } from '../users/users.module';

@Module({
  imports: [UsersModule], // on importe le module
  providers: [AuthService],
})
export class AuthModule {}

AuthService

@Injectable()
export class AuthService {
  constructor(private usersService: UsersService) {}

  login(email: string) {
    return this.usersService.findAll();
  }
}

Enfin, pour utiliser un service d’un autre module :

  • Le service doit être dans providers
  • Il doit être dans exports
  • Le module consommateur doit l’ajouter dans imports

Ensuite on peut l’injecter via le constructeur


En quoi est-ce important ?

Avec DI :

  • NestJS gère le cycle de vie.
  • Les dépendances sont centralisées.
  • Les services sont facilement remplaçables (mock pour tests).

sans DI :

  • Les classes créeraient elles-mêmes leurs dépendances.
  • Le code serait fortement couplé.
  • Les tests unitaires seraient difficiles.

La dependency injection dans NestJS repose sur :

✔ les décorateurs (@Injectable())

✔ la configuration des modules (providers, exports, imports)

✔ l’injection via le constructeur

C’est un mécanisme central qui structure l’architecture de l’application.