Introduction à NestJS : Pourquoi ce framework ?

Introduction à NestJS : Pourquoi ce framework ?

NestJS est un framework Node.js créé par Kamil Myśliwiec en 2017. Son idée de départ : prendre ce qui fonctionne dans Angular — modules, décorateurs, injection de dépendances — et l'appliquer côté serveur. Le résultat est un framework qui impose une architecture claire dès le premier fichier, tout en restant compatible avec l'écosystème Express (ou Fastify).

Cet article explore ce qui rend NestJS différent des autres frameworks Node.js, pourquoi il séduit de plus en plus d'équipes, et dans quels cas il est le bon choix. On illustrera avec des exemples tirés d'un vrai projet de production : une API de réservation en ligne construite avec NestJS, TypeORM et PostgreSQL.

Prérequis : connaissances de base en JavaScript/TypeScript. Aucune expérience NestJS requise — c'est justement le but de cet article.

Le problème que résout NestJS

Express.js est le framework Node.js le plus utilisé, et pour cause : il est léger, flexible et facile à prendre en main. Mais cette flexibilité devient un piège quand le projet grandit :

  • Pas de structure imposée — chaque développeur organise le code différemment
  • Pas d'injection de dépendances native — les dépendances sont souvent importées directement
  • Pas de système de modules — tout finit dans un gros fichier app.js ou un arbre de dossiers improvisé
  • TypeScript en option — il faut le configurer soi-même

NestJS répond à chacun de ces points en imposant une architecture modulaire et déclarative, inspirée des frameworks backend matures comme Spring (Java) ou Symfony (PHP).

L'architecture en trois briques

Toute application NestJS repose sur trois concepts fondamentaux : les modules, les controllers et les services. Prenons un exemple concret.

Le Module : regrouper les fonctionnalités

Un module est un conteneur qui regroupe un ensemble cohérent de fonctionnalités. Voici le module principal d'un projet de production :

import { Module } from '@nestjs/common';
import { ConfigModule } from '@nestjs/config';
import { ThrottlerModule } from '@nestjs/throttler';
import { DatabaseModule } from './database/database.module';
import { AuthModule } from './modules/auth/auth.module';
import { BookingModule } from './modules/booking/booking.module';
import { ServicesModule } from './modules/services/services.module';
import { PaymentModule } from './modules/payment/payment.module';
import { ContactModule } from './modules/contact/contact.module';
import configuration from './config/configuration';

@Module({
  imports: [
    ConfigModule.forRoot({
      isGlobal: true,
      load: [configuration],
    }),
    ThrottlerModule.forRoot([{
      ttl: 60000,   // 1 minute
      limit: 100,   // 100 requêtes max
    }]),
    DatabaseModule,
    AuthModule,
    ServicesModule,
    BookingModule,
    PaymentModule,
    ContactModule,
    // ... 12 autres modules
  ],
})
export class AppModule {}

Le décorateur @Module déclare les dépendances du module : quels autres modules il importe, quels controllers il expose, quels services il fournit. C'est la carte d'identité de chaque fonctionnalité.

Le Controller : gérer les requêtes HTTP

Un controller reçoit les requêtes HTTP et délègue le travail au service. Il ne contient aucune logique métier — juste du routage et de la validation :

import { Controller, Get, Post, Body, Param } from '@nestjs/common';
import { AppService } from './app.service';

@Controller()
export class AppController {
  constructor(private readonly appService: AppService) {}

  @Get('health')
  getHealth(): string {
    return this.appService.getHealth();
  }
}

Les décorateurs @Get, @Post, @Put, @Delete remplacent les app.get(), app.post() d'Express. C'est plus lisible et ça se documente automatiquement avec Swagger.

Le Service : la logique métier

Le service contient la vraie logique. Il est marqué @Injectable() pour que NestJS puisse l'injecter automatiquement dans les controllers (ou d'autres services) :

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

@Injectable()
export class AppService {
  getHealth(): string {
    return 'API is running';
  }
}

Cette séparation controller/service est le Single Responsibility Principle appliqué : le controller s'occupe du HTTP, le service s'occupe du métier. Quand vous testez, vous pouvez mocker le service sans toucher au HTTP.

L'injection de dépendances : le cœur du système

L'injection de dépendances (DI) est ce qui distingue NestJS d'Express. Au lieu d'importer directement vos dépendances :

// ❌ Express : import direct, couplage fort
import { UserRepository } from '../repositories/user.repository';

export function getUser(id: string) {
  const repo = new UserRepository();  // impossible à mocker
  return repo.findById(id);
}

NestJS injecte les dépendances via le constructeur :

// ✅ NestJS : injection, découplage, testabilité
@Injectable()
export class UserService {
  constructor(
    @InjectRepository(User)
    private readonly userRepository: Repository<User>,
  ) {}

  async findById(id: string): Promise<User> {
    return this.userRepository.findOneBy({ id });
  }
}

Le conteneur IoC (Inversion of Control) de NestJS résout automatiquement les dépendances. Quand vous déclarez UserService comme provider d'un module, NestJS sait créer l'instance avec toutes ses dépendances résolues.

NestJS vs Express : ce que NestJS apporte

Voici une comparaison concrète sur un projet de taille moyenne (10+ routes, base de données, auth) :

  • Structure : NestJS impose modules/controllers/services dès le départ. Express vous laisse libre — ce qui signifie que chaque projet a une structure différente.
  • TypeScript natif : NestJS est écrit en TypeScript. Vous avez le typage, l'autocomplétion et la vérification à la compilation sans configuration supplémentaire.
  • Testabilité : grâce à la DI, mocker une dépendance dans un test se fait en une ligne. En Express, il faut souvent contourner les imports.
  • Écosystème intégré : @nestjs/typeorm pour la base de données, @nestjs/jwt pour l'auth, @nestjs/swagger pour la doc — tout s'intègre de manière cohérente.
  • Documentation auto : Swagger génère une documentation interactive à partir de vos décorateurs. Elle est typiquement accessible à /api/docs.

Les cas d'usage idéaux

NestJS est particulièrement adapté pour :

  • APIs REST — c'est son terrain de jeu principal. La structure modulaire et les décorateurs rendent le code lisible et maintenable.
  • Microservices — NestJS supporte nativement les transports TCP, Redis, NATS, gRPC via @nestjs/microservices.
  • Applications temps réel — le support natif de WebSockets (via @nestjs/websockets) permet de construire des applications interactives.
  • Applications fullstack — couplé à un frontend React/Next.js (comme Next.js ou React), NestJS fournit un backend solide et typé.

En revanche, pour un simple script, une CLI ou un prototype rapide, Express ou Fastify seul reste plus léger.

L'écosystème NestJS

Un projet de production typique utilise une bonne partie de l'écosystème officiel. Voici les packages clés et leur rôle :

{
  "@nestjs/core": "11.0.1",        // Le cœur du framework
  "@nestjs/config": "4.0.2",       // Gestion des variables d'environnement
  "@nestjs/typeorm": "11.0.0",     // Intégration TypeORM (PostgreSQL)
  "@nestjs/jwt": "11.0.1",         // Authentification JWT
  "@nestjs/swagger": "11.2.3",     // Documentation API auto-générée
  "@nestjs/throttler": "6.4.0",    // Rate limiting (anti-DDoS)
  "@nestjs/serve-static": "5.0.1", // Servir les fichiers uploadés
  "@nestjs-modules/mailer": "2.0.2" // Envoi d'emails
}

Ce qui frappe, c'est la cohérence : tous ces packages suivent les mêmes conventions, s'intègrent via le même système de modules, et se configurent de la même manière. Pas de surprise.

La CLI : productivité dès le premier jour

La CLI NestJS génère automatiquement les fichiers avec la bonne structure :

# Installer la CLI
npm install -g @nestjs/cli

# Créer un nouveau projet
nest new mon-projet

# Générer un module complet (controller + service + module + DTO)
nest generate resource booking

# Générer un composant isolé
nest generate controller users
nest generate service users
nest generate module users

La commande nest generate resource est particulièrement puissante : elle crée un module fonctionnel avec toutes les opérations CRUD prêtes à être complétées.

Pourquoi les entreprises adoptent NestJS

La vraie force de NestJS apparaît quand l'équipe grandit ou que le projet vieillit :

  • Onboarding rapide : un nouveau développeur comprend la structure en 5 minutes. Chaque module a le même layout.
  • Maintenabilité : modifier un module n'impacte pas les autres. Les dépendances sont explicites.
  • Scalabilité : ajouter une fonctionnalité = créer un nouveau module. Un projet typique peut en avoir 18 et reste organisé.
  • Tests : l'architecture facilite les tests unitaires et E2E. Le framework fournit @nestjs/testing avec des utilitaires dédiés.

Conclusion

NestJS n'est pas juste "Express avec des décorateurs". C'est un changement de paradigme : au lieu de construire une structure ad-hoc qui finira par s'effondrer sous son propre poids, vous démarrez avec une architecture modulaire, typée et testable dès le premier fichier.

Un projet de production — avec ses 18 modules, son auth JWT, ses paiements Stripe, et sa doc Swagger — illustre ce que NestJS permet de construire de manière organisée. Dans les prochains articles, nous verrons comment créer un projet NestJS de zéro, puis comment implémenter chacune de ces briques.

Pour approfondir : documentation officielle NestJS.

Commentaires

Soyez le premier à laisser un commentaire !

Laisser un commentaire

Les champs obligatoires sont indiqués avec *