Decorateur de parametre qui extrait le corps de la requete HTTP et le mappe sur un DTO. Peut cibler une propriete specifique avec @Body('key').
Comme ouvrir un colis et en extraire le contenu pour le traiter.
@Post()
create(@Body() dto: CreateUserDto) {
return this.userService.create(dto);
}
@Post('login')
login(@Body('email') email: string) {
return this.authService.login(email);
}Cas d'usage : Recevoir les donnees envoyees par le client dans les requetes POST, PUT ou PATCH.
Decorateurs de methode qui mappent les methodes HTTP aux handlers du controller. Chacun definit le verbe HTTP et le chemin optionnel de la route.
Comme les panneaux directionnels dans un aeroport : chacun oriente vers la bonne porte d'embarquement.
@Controller('items')
export class ItemController {
@Get() findAll() { /* ... */ }
@Post() create(@Body() dto: CreateItemDto) { /* ... */ }
@Put(':id') update(@Param('id') id: string) { /* ... */ }
@Delete(':id') remove(@Param('id') id: string) { /* ... */ }
}Cas d'usage : Definir les operations CRUD standard sur une ressource REST.
Decorateur de parametre qui extrait les headers HTTP de la requete. Peut cibler un header specifique par nom ou recuperer tous les headers.
Comme lire l'etiquette sur un colis pour connaitre l'expediteur et le contenu.
@Get()
getData(@Headers('authorization') auth: string) {
return this.service.getData(auth);
}Cas d'usage : Extraire les tokens d'authentification, API keys ou headers custom des requetes.
Decorateur qui specifie le token d'injection pour un parametre de constructeur. Necessaire pour les providers enregistres avec un token string ou symbol.
Comme preciser le nom exact du fournisseur quand il y a plusieurs pour le meme type de service.
@Injectable()
export class AppService {
constructor(
@Inject('DATABASE_CONNECTION')
private db: Connection,
) {}
}Cas d'usage : Injecter des providers enregistres avec useValue/useFactory qui utilisent des tokens string.
Decorateur qui marque une classe comme injectable par le conteneur DI de NestJS. Obligatoire pour tout provider qui participe a l'injection de dependances.
Comme un badge professionnel : sans lui, le systeme ne te reconnait pas comme employe.
@Injectable()
export class AppService {
getHello(): string {
return 'Hello World!';
}
}Cas d'usage : Annoter chaque service, guard, interceptor, pipe et tout provider custom.
Decorateur de parametre qui extrait les parametres de route de l'URL (ex: /users/:id). Peut cibler un parametre specifique ou recuperer tous les params.
Comme lire le numero de chambre sur la cle d'hotel pour savoir ou aller.
@Get(':id')
findOne(@Param('id', ParseIntPipe) id: number) {
return this.userService.findOne(id);
}Cas d'usage : Extraire les identifiants de ressources ou slugs depuis les URLs REST.
Decorateur de parametre qui extrait les query parameters de l'URL (ex: ?page=1&limit=10). Supporte la transformation via pipes.
Comme les filtres de recherche sur un site e-commerce : ils affinent les resultats sans changer la page.
@Get()
findAll(
@Query('page', new DefaultValuePipe(1), ParseIntPipe) page: number,
@Query('limit', new DefaultValuePipe(10), ParseIntPipe) limit: number,
) { return this.service.paginate(page, limit); }Cas d'usage : Implementer la pagination, le tri et le filtrage sur les endpoints de liste.
Decorateur qui attache des metadonnees personnalisees a un handler ou controller, lisibles via Reflector dans les guards ou interceptors.
Comme coller une etiquette 'VIP' ou 'Public' sur une porte pour que le vigile sache qui laisser entrer.
export const Roles = (...roles: string[]) =>
SetMetadata('roles', roles);
@Post()
@Roles('admin')
create() { /* ... */ }Cas d'usage : Definir les roles requis sur un endpoint pour les verifier dans un RolesGuard.
Decorateur qui attache un ou plusieurs filtres d'exception a un controller ou handler pour intercepter et formater les erreurs specifiques.
Comme un traducteur qui reformule les erreurs techniques en messages comprehensibles pour le client.
@Controller('users')
@UseFilters(new HttpExceptionFilter())
export class UserController {
@Post()
create(@Body() dto: CreateUserDto) {
return this.service.create(dto);
}
}Cas d'usage : Appliquer un format d'erreur personnalise pour un domaine specifique de l'API.
Decorateur qui attache un ou plusieurs guards a un controller ou un handler. Les guards s'executent avant le handler pour autoriser ou refuser l'acces.
Comme placer un vigile devant une porte specifique ou a l'entree de tout le batiment.
@Controller('admin')
@UseGuards(AuthGuard, RolesGuard)
export class AdminController {
@Get('dashboard')
getDashboard() { return 'admin data'; }
}Cas d'usage : Proteger un controller entier ou des routes specifiques avec authentification et autorisation.
Decorateur qui attache un ou plusieurs interceptors a un controller ou handler pour transformer les requetes/reponses ou ajouter des comportements transversaux.
Comme ajouter un filtre Instagram a une photo : le contenu est le meme mais la presentation change.
@Controller('users')
@UseInterceptors(CacheInterceptor)
export class UserController {
@Get()
@UseInterceptors(ClassSerializerInterceptor)
findAll() { return this.service.findAll(); }
}Cas d'usage : Appliquer la serialisation, le cache ou le logging sur des routes specifiques.
Decorateur qui attache un ou plusieurs pipes a un controller ou handler pour valider ou transformer les donnees entrantes automatiquement.
Comme un detecteur de metaux a l'entree : il filtre automatiquement tout ce qui n'est pas conforme.
@Post()
@UsePipes(new ValidationPipe({ whitelist: true }))
create(@Body() dto: CreateUserDto) {
return this.service.create(dto);
}Cas d'usage : Activer la validation automatique des DTOs avec class-validator sur des routes specifiques.
Attribute-Based Access Control : systeme d'autorisation base sur les attributs du sujet, de la ressource et du contexte. Plus flexible que RBAC.
Comme une boite de nuit avec des regles complexes : age + tenue + liste VIP + heure determinant l'acces.
// Regle ABAC: l'auteur peut modifier son propre article
canActivate(ctx: ExecutionContext) {
const user = ctx.switchToHttp().getRequest().user;
const articleId = ctx.switchToHttp().getRequest().params.id;
const article = await this.articleService.findOne(articleId);
return article.authorId === user.id;
}Cas d'usage : Implementer des regles d'autorisation fines comme 'un auteur ne peut modifier que ses propres articles'.
Module pour gerer des queues de jobs asynchrones via Redis et Bull/BullMQ. Permet le traitement en arriere-plan avec retries et scheduling.
Comme une file d'attente au guichet : les taches arrivent, sont traitees dans l'ordre et reessayees si besoin.
@Processor('email')
export class EmailProcessor {
@Process()
async sendEmail(job: Job<EmailData>) {
await this.mailer.send(job.data);
}
}
// Ajout en queue
await this.emailQueue.add({ to: 'user@mail.com', subject: 'Hello' });Cas d'usage : Traiter l'envoi d'emails, le redimensionnement d'images ou les exports CSV en arriere-plan.
Module de cache integre qui supporte le cache en memoire ou via des stores externes (Redis). Utilise des interceptors pour cacher les reponses automatiquement.
Comme un post-it avec les reponses frequentes : plus rapide que de recalculer a chaque fois.
@Module({
imports: [CacheModule.register({
store: redisStore,
host: 'localhost',
ttl: 60,
})],
})
export class AppModule {}
@UseInterceptors(CacheInterceptor)
@Get()
findAll() { return this.service.findAll(); }Cas d'usage : Cacher les reponses de endpoints lourds comme les listes avec pagination pour reduire la charge DB.
Librairie d'autorisation isomorphe qui definit les abilities (permissions) de facon declarative. S'integre avec NestJS via un guard custom.
Comme un reglement interieur detaille : chaque personne sait exactement ce qu'elle peut et ne peut pas faire.
const ability = defineAbility((can, cannot) => {
can('read', 'Article');
can('update', 'Article', { authorId: user.id });
cannot('delete', 'Article');
});
// ability.can('update', article) -> true/falseCas d'usage : Gerer des permissions granulaires avec des conditions sur les champs des entites.
Situation ou deux providers ou modules dependent mutuellement l'un de l'autre, causant une erreur de resolution. Se resout avec forwardRef.
Comme deux personnes bloquees a une porte, chacune attendant que l'autre passe en premier.
// Module A importe B, B importe A
@Module({
imports: [forwardRef(() => ModuleB)],
})
export class ModuleA {}Cas d'usage : Resoudre temporairement une dependance circulaire tout en planifiant un refactoring pour l'eliminer.
Abstraction pour communiquer avec d'autres microservices via send() (request-reply) ou emit() (event-based). Injectee via ClientsModule.
Comme un telephone interne d'entreprise : tu appelles un autre service et attends (send) ou laisses un message (emit).
@Injectable()
export class OrderService {
constructor(@Inject('PAYMENT_SERVICE') private client: ClientProxy) {}
processPayment(order: Order) {
return this.client.send('process_payment', order);
}
notifyShipping(order: Order) {
this.client.emit('order_shipped', order);
}
}Cas d'usage : Appeler des microservices distants depuis un service NestJS de facon decouple.
Module officiel @nestjs/config pour gerer les variables d'environnement. Charge les fichiers .env et fournit ConfigService pour l'injection.
Comme un coffre-fort d'entreprise : centralise tous les secrets et parametres, accessible uniquement aux autorises.
@Module({
imports: [ConfigModule.forRoot({
isGlobal: true,
validationSchema: Joi.object({
DB_HOST: Joi.string().required(),
DB_PORT: Joi.number().default(5432),
}),
})],
})
export class AppModule {}Cas d'usage : Centraliser et valider toutes les variables d'environnement au demarrage de l'application.
Technique de reutilisation de connexions base de donnees via un pool precharge. Evite le cout de creation/destruction de connexions a chaque requete.
Comme un parc de voitures partagees : au lieu que chacun achete sa voiture, on partage un pool.
TypeOrmModule.forRoot({
type: 'postgres',
host: 'localhost',
extra: {
max: 20,
idleTimeoutMillis: 30000,
},
})Cas d'usage : Optimiser les performances en production en configurant le pool selon la charge attendue.
Classe decoree @Controller qui gere les requetes HTTP entrantes et retourne les reponses. Chaque methode est mappee a une route via des decorateurs HTTP.
Comme un receptionniste d'hotel : il recoit les demandes des clients et les redirige vers le bon service.
@Controller('users')
export class UserController {
constructor(private userService: UserService) {}
@Get(':id')
findOne(@Param('id') id: string) {
return this.userService.findOne(id);
}
}Cas d'usage : Definir les endpoints REST de l'API et deleguer la logique metier aux services.
Cross-Origin Resource Sharing : mecanisme HTTP qui permet a un frontend sur un domaine different d'acceder a l'API. Configure via app.enableCors().
Comme un visa d'entree : il autorise les visiteurs de certains pays (origines) a acceder au territoire (API).
app.enableCors({
origin: ['https://monsite.com', 'https://admin.monsite.com'],
methods: ['GET', 'POST', 'PUT', 'DELETE'],
credentials: true,
});Cas d'usage : Permettre au frontend SPA sur un autre domaine de communiquer avec l'API backend.
Methode de Test.createTestingModule qui cree un module NestJS isole pour les tests. Permet de mocker les dependances via overrideProvider.
Comme un simulateur de vol : tu recrees l'environnement complet mais en mode test.
const module = await Test.createTestingModule({
providers: [UserService,
{ provide: UserRepository, useValue: mockRepo }],
}).compile();
const service = module.get<UserService>(UserService);
expect(await service.findAll()).toEqual([]);Cas d'usage : Ecrire des tests unitaires et d'integration pour les services NestJS avec des mocks.
Cross-Site Request Forgery : attaque ou un site malveillant force le navigateur a envoyer des requetes authentifiees. Protege via des tokens anti-CSRF.
Comme quelqu'un qui forge ta signature pour signer un cheque a ta place sans que tu le saches.
import csurf from 'csurf';
app.use(csurf({ cookie: true }));
// Le token CSRF est envoye au client et verifie a chaque mutationCas d'usage : Proteger les applications avec sessions/cookies contre les requetes forgees.
Decorateur personalise cree avec createParamDecorator ou applyDecorators pour extraire des donnees ou combiner des decorateurs existants.
Comme creer un raccourci clavier personnalise qui combine plusieurs actions en un seul geste.
export const CurrentUser = createParamDecorator(
(data: unknown, ctx: ExecutionContext) => {
const request = ctx.switchToHttp().getRequest();
return request.user;
},
);Cas d'usage : Extraire l'utilisateur courant du token JWT dans chaque handler sans dupliquer le code.
Providers definis avec useClass, useValue, useFactory ou useExisting pour un controle total sur ce qui est injecte. Permet l'injection de valeurs non-classes.
Comme choisir entre acheter un meuble en kit, le faire sur mesure ou recycler un ancien meuble.
providers: [
{ provide: 'API_KEY', useValue: process.env.API_KEY },
{ provide: Logger, useClass: ProdLogger },
{ provide: 'DB', useFactory: (cfg: ConfigService) =>
createConnection(cfg.get('DB_URL')),
inject: [ConfigService],
},
]Cas d'usage : Injecter des variables d'environnement, des connexions dynamiques ou des implementations alternatives.
Utilitaire qui regroupe et met en cache les requetes de base de donnees dans une execution GraphQL. Resout le probleme classique N+1.
Comme un livreur qui regroupe toutes les commandes d'un quartier en une seule tournee au lieu de faire un aller-retour par colis.
@Injectable({ scope: Scope.REQUEST })
export class UserLoader {
private loader = new DataLoader<number, User>(async (ids) => {
const users = await this.userService.findByIds([...ids]);
return ids.map(id => users.find(u => u.id === id));
});
load(id: number) { return this.loader.load(id); }
}Cas d'usage : Optimiser les resolvers GraphQL en batchant les requetes par entite pour eviter le N+1.
Pattern ou les dependances sont fournies a une classe par le framework plutot que creees par la classe elle-meme. NestJS utilise l'injection par constructeur.
Comme un restaurant ou les ingredients sont livres par les fournisseurs plutot que cultives par le chef.
@Injectable()
export class OrderService {
constructor(
private userService: UserService,
private paymentService: PaymentService,
) {}
}Cas d'usage : Decouple les classes pour faciliter les tests unitaires et permettre le remplacement des implementations.
Module configurable via une methode statique (forRoot/forRootAsync) qui retourne un DynamicModule. Permet de passer des options de configuration a l'import.
Comme un abonnement telephonique : le meme operateur mais tu choisis ton forfait (options) a la souscription.
@Module({})
export class MailModule {
static forRoot(config: MailConfig): DynamicModule {
return {
module: MailModule,
providers: [{ provide: 'MAIL_CONFIG', useValue: config }, MailService],
exports: [MailService],
};
}
}Cas d'usage : Creer des modules reutilisables comme les modules de config, cache ou mail avec des parametres variables.
Tests end-to-end qui simulent de vraies requetes HTTP via la librairie supertest. Testent le pipeline complet du request au response.
Comme un client mystere qui teste le restaurant de A a Z : de la reservation au dessert.
const app = moduleFixture.createNestApplication();
await app.init();
await request(app.getHttpServer())
.post('/users')
.send({ email: 'test@test.com', password: '12345678' })
.expect(201)
.expect(res => expect(res.body.email).toBe('test@test.com'));Cas d'usage : Valider que les endpoints, la validation, les guards et la serialisation fonctionnent ensemble.
Module pour la communication asynchrone intra-application via evenements. Les services emettent des evenements et les listeners les traitent de facon decouple.
Comme un systeme de haut-parleurs dans un batiment : un message est diffuse et ceux concernes reagissent.
// Emission
this.eventEmitter.emit('order.created', new OrderCreatedEvent(order));
// Listener
@OnEvent('order.created')
async handleOrderCreated(event: OrderCreatedEvent) {
await this.emailService.sendConfirmation(event.order);
}Cas d'usage : Decoupler les effets de bord (email, notifications) de la logique metier principale.
Classe decoree @Catch qui intercepte les exceptions non gerees et les transforme en reponses HTTP structurees. Centralise la gestion d'erreurs.
Comme un filet de securite sous un trapeziste : il attrape les chutes et les transforme en atterrissage controle.
@Catch(HttpException)
export class HttpExceptionFilter implements ExceptionFilter {
catch(exception: HttpException, host: ArgumentsHost) {
const ctx = host.switchToHttp();
const response = ctx.getResponse();
response.status(exception.getStatus()).json({
message: exception.message,
});
}
}Cas d'usage : Formater toutes les erreurs API de maniere coherente avec des codes d'erreur et messages standardises.
Fonction utilitaire qui resout les dependances circulaires en retardant la resolution de la reference. Utilise un wrapper de fonction pour differer l'evaluation.
Comme dire 'je te presenterai mon collegue quand il arrivera' plutot que d'exiger sa presence immediate.
@Injectable()
export class CatService {
constructor(
@Inject(forwardRef(() => DogService))
private dogService: DogService,
) {}
}Cas d'usage : Resoudre les dependances circulaires entre deux services ou modules qui se referent mutuellement.
Module decore avec @Global() dont les providers sont accessibles dans toute l'application sans import explicite. A utiliser avec parcimonie.
Comme le WiFi dans un hotel : disponible partout sans avoir a le demander a chaque etage.
@Global()
@Module({
providers: [ConfigService],
exports: [ConfigService],
})
export class ConfigModule {}Cas d'usage : Exposer des services transversaux comme la configuration ou le logging sans imports repetitifs.
Decorateur pour definir des abonnements temps reel via WebSocket dans GraphQL. Permet au client de recevoir des mises a jour en push.
Comme un flux d'actualites en direct : tu t'abonnes une fois et les nouvelles arrivent automatiquement.
@Subscription(() => Comment, {
filter: (payload, variables) =>
payload.commentAdded.postId === variables.postId,
})
commentAdded(@Args('postId') postId: string) {
return this.pubSub.asyncIterator('commentAdded');
}Cas d'usage : Implementer des notifications temps reel comme les nouveaux commentaires ou messages.
Classe decoree @Resolver qui definit les operations GraphQL (queries, mutations, subscriptions) en approche code-first avec des decorateurs TypeScript.
Comme un serveur de restaurant avec un menu a la carte : le client choisit exactement ce qu'il veut recevoir.
@Resolver(() => User)
export class UserResolver {
constructor(private userService: UserService) {}
@Query(() => [User])
users() { return this.userService.findAll(); }
@Mutation(() => User)
createUser(@Args('input') input: CreateUserInput) {
return this.userService.create(input);
}
}Cas d'usage : Exposer une API GraphQL code-first avec typage automatique du schema depuis TypeScript.
Framework RPC haute performance utilisant Protocol Buffers et HTTP/2. NestJS supporte gRPC comme transport pour les microservices.
Comme un langage signe standardise entre machines : ultra-rapide et compact, mais moins lisible pour les humains.
@GrpcMethod('UserService', 'FindOne')
findOne(data: { id: number }): User {
return this.userService.findOne(data.id);
}
// .proto: service UserService {
// rpc FindOne (UserById) returns (User);
// }Cas d'usage : Communiquer entre microservices avec des performances superieures a REST et un contrat strict.
Classe @Injectable implementant CanActivate qui decide si une requete peut continuer. Ideal pour l'authentification et l'autorisation.
Comme un videur de boite de nuit : il verifie si tu as le droit d'entrer avant de te laisser passer.
@Injectable()
export class AuthGuard implements CanActivate {
canActivate(context: ExecutionContext): boolean {
const request = context.switchToHttp().getRequest();
return !!request.headers.authorization;
}
}Cas d'usage : Proteger des routes avec authentification JWT, verifier les roles RBAC ou valider des permissions.
Middleware qui securise les headers HTTP (X-Frame-Options, CSP, HSTS, etc.). Protege contre les attaques web courantes comme le clickjacking.
Comme un casque de moto : protection basique mais indispensable contre les dangers les plus courants.
// main.ts
import helmet from 'helmet';
async function bootstrap() {
const app = await NestFactory.create(AppModule);
app.use(helmet());
await app.listen(3000);
}Cas d'usage : Ajouter les headers de securite HTTP standard a toute API NestJS en production.
Application NestJS qui combine un serveur HTTP et un ou plusieurs microservices dans le meme processus. Ecoute sur plusieurs transports simultanement.
Comme un restaurant avec salle et livraison : le meme service cuisine mais repond a deux canaux differents.
const app = await NestFactory.create(AppModule);
app.connectMicroservice({ transport: Transport.REDIS,
options: { host: 'localhost', port: 6379 } });
await app.startAllMicroservices();
await app.listen(3000);Cas d'usage : Migrer progressivement vers une architecture microservices en gardant l'API HTTP existante.
Definit le cycle de vie d'un provider : DEFAULT (singleton), REQUEST (par requete) ou TRANSIENT (nouvelle instance a chaque injection).
Comme un bureau : partage (singleton), un par client (request) ou jetable apres chaque usage (transient).
@Injectable({ scope: Scope.REQUEST })
export class RequestLogger {
private requestId = randomUUID();
log(msg: string) {
console.log(`[${this.requestId}] ${msg}`);
}
}Cas d'usage : Utiliser REQUEST scope pour des services qui doivent stocker des donnees specifiques a chaque requete.
Classe implementant NestInterceptor qui enveloppe l'execution du handler via RxJS. Peut transformer la reponse, ajouter du logging ou gerer le cache.
Comme un emballeur cadeau : le produit (reponse) passe par lui avant et apres pour etre transforme.
@Injectable()
export class TransformInterceptor implements NestInterceptor {
intercept(ctx: ExecutionContext, next: CallHandler) {
return next.handle().pipe(
map(data => ({ data, timestamp: Date.now() })),
);
}
}Cas d'usage : Wrapper toutes les reponses dans un format standard, mesurer le temps de reponse ou implementer du cache.
Le conteneur d'Inversion de Controle de NestJS qui gere la creation, la resolution et le cycle de vie de tous les providers enregistres.
Comme un annuaire professionnel : tu demandes un plombier et l'annuaire te fournit le bon contact.
// NestJS resout automatiquement le graphe de dependances
// UserController -> UserService -> UserRepository
// Il suffit de declarer les types dans le constructeur
@Injectable()
export class UserService {
constructor(private repo: UserRepository) {}
}Cas d'usage : Laisser le framework gerer la creation et l'injection de toutes les instances de l'application.
Strategie Passport qui valide les tokens JWT extraits du header Authorization. Decode le payload et l'attache a request.user.
Comme un scanner de badge electronique : il lit le badge (token), verifie sa validite et identifie la personne.
@Injectable()
export class JwtStrategy extends PassportStrategy(Strategy) {
constructor(config: ConfigService) {
super({ jwtFromRequest: ExtractJwt.fromAuthHeaderAsBearerToken(),
secretOrKey: config.get('JWT_SECRET') });
}
validate(payload: any) { return { id: payload.sub, email: payload.email }; }
}Cas d'usage : Proteger les endpoints API avec authentification stateless par token JWT.
Interfaces (OnModuleInit, OnModuleDestroy, OnApplicationBootstrap, OnApplicationShutdown) qui permettent d'executer du code a des moments cles du cycle de vie.
Comme les etapes d'ouverture et fermeture d'un magasin : mise en place le matin, rangement le soir.
@Injectable()
export class DbService implements OnModuleInit, OnModuleDestroy {
async onModuleInit() {
await this.connect();
}
async onModuleDestroy() {
await this.disconnect();
}
}Cas d'usage : Initialiser des connexions base de donnees au demarrage et les fermer proprement a l'arret.
Strategie Passport qui authentifie via email/mot de passe. Valide les credentials contre la base de donnees et retourne l'utilisateur.
Comme presenter sa carte d'identite et son mot de passe a un guichet pour prouver son identite.
@Injectable()
export class LocalStrategy extends PassportStrategy(Strategy) {
constructor(private authService: AuthService) { super(); }
async validate(username: string, password: string) {
const user = await this.authService.validateUser(username, password);
if (!user) throw new UnauthorizedException();
return user;
}
}Cas d'usage : Implementer le login classique par email et mot de passe avant d'emettre un JWT.
@MessagePattern attend une reponse (request-reply) tandis que @EventPattern est fire-and-forget (event-based). Deux paradigmes de communication inter-services.
Comme envoyer un recommande avec accuse de reception (message) vs jeter une bouteille a la mer (event).
// Request-reply: l'appelant attend une reponse
@MessagePattern('get_user')
getUser(data: { id: number }) {
return this.userService.findOne(data.id);
}
// Fire-and-forget: pas de reponse attendue
@EventPattern('user_created')
handleUserCreated(data: UserCreatedEvent) {
this.emailService.sendWelcome(data.email);
}Cas d'usage : Utiliser MessagePattern pour les queries et EventPattern pour les notifications asynchrones.
Fonction ou classe executee avant le route handler, avec acces a request, response et next(). Compatible avec les middlewares Express/Fastify.
Comme un agent de securite a l'entree d'un immeuble : il verifie ton badge avant de te laisser monter.
@Injectable()
export class LoggerMiddleware implements NestMiddleware {
use(req: Request, res: Response, next: NextFunction) {
console.log(`${req.method} ${req.url}`);
next();
}
}Cas d'usage : Logger les requetes, parser des headers custom ou modifier la requete avant qu'elle atteigne le controller.
Classe annotee @Module qui organise l'application en blocs fonctionnels cohesifs. Chaque module declare ses controllers, providers, imports et exports.
Comme un departement dans une entreprise : chaque departement a ses employes, ses outils et ses responsabilites bien definies.
@Module({
imports: [DatabaseModule],
controllers: [UserController],
providers: [UserService],
exports: [UserService],
})
export class UserModule {}Cas d'usage : Structurer chaque domaine metier en module dedie pour maintenir la separation des responsabilites.
Interface pour interagir avec une collection MongoDB, injectee via @InjectModel. Fournit les methodes CRUD (find, create, updateOne, deleteMany).
Comme un guichet dedie a une collection : il sait lire, ecrire et supprimer les documents de sa collection.
@Injectable()
export class CatService {
constructor(
@InjectModel(Cat.name) private catModel: Model<Cat>,
) {}
create(dto: CreateCatDto) {
return new this.catModel(dto).save();
}
}Cas d'usage : Effectuer les operations CRUD sur les collections MongoDB dans un service NestJS.
Mecanisme pour charger automatiquement les documents references depuis d'autres collections. Equivalent des jointures SQL pour MongoDB.
Comme des liens hypertexte dans un document : cliquer dessus charge le contenu reference.
async findWithOwner(id: string) {
return this.catModel
.findById(id)
.populate('owner')
.exec();
}Cas d'usage : Charger les documents lies sans faire plusieurs requetes manuelles.
Definition de la structure d'un document MongoDB via @Schema et @Prop de @nestjs/mongoose. Genere le schema Mongoose a partir des decorateurs TypeScript.
Comme un formulaire avec des champs obligatoires et optionnels : il definit ce qu'un document doit contenir.
@Schema({ timestamps: true })
export class Cat {
@Prop({ required: true })
name: string;
@Prop()
age: number;
@Prop({ type: Types.ObjectId, ref: 'Owner' })
owner: Owner;
}Cas d'usage : Definir la structure des documents MongoDB avec validation et typage TypeScript.
Strategie Passport pour l'authentification via providers tiers (Google, GitHub, Facebook). Gere le flow d'autorisation OAuth2 avec callback.
Comme se connecter a un hotel avec sa carte de membre d'une chaine : un tiers de confiance confirme ton identite.
@Injectable()
export class GoogleStrategy extends PassportStrategy(Strategy, 'google') {
constructor(cfg: ConfigService) {
super({ clientID: cfg.get('GOOGLE_ID'),
clientSecret: cfg.get('GOOGLE_SECRET'),
callbackURL: '/auth/google/callback',
scope: ['email', 'profile'] });
}
validate(token, refresh, profile) { return profile; }
}Cas d'usage : Proposer le 'Login with Google/GitHub' pour simplifier l'onboarding utilisateur.
Dependances marquees @Optional() qui ne causent pas d'erreur si elles ne sont pas enregistrees. Le provider recoit undefined si absent.
Comme commander un burger avec 'fromage en option' : si y'en a pas, tu recois quand meme ton burger.
@Injectable()
export class NotificationService {
constructor(
@Optional() @Inject('SMS_SERVICE')
private sms?: SmsService,
) {}
}Cas d'usage : Implementer des fonctionnalites optionnelles comme les notifications SMS qui ne sont pas toujours configurees.
Methode du TestingModule pour remplacer un guard par une implementation permissive dans les tests. Permet de tester les handlers sans authentification.
Comme desactiver le badge d'acces pendant les tests incendie pour que tout le monde puisse circuler.
const module = await Test.createTestingModule({
imports: [AppModule],
}).overrideGuard(AuthGuard)
.useValue({ canActivate: () => true })
.compile();Cas d'usage : Tester les endpoints proteges sans avoir a generer de vrais tokens JWT.
Methode du TestingModule pour remplacer un provider par un mock ou une implementation alternative dans les tests.
Comme remplacer un acteur par sa doublure pour une scene dangereuse : le role est le meme, l'implementation change.
const module = await Test.createTestingModule({
imports: [UserModule],
}).overrideProvider(UserService)
.useValue({ findAll: jest.fn().mockResolvedValue([]) })
.compile();Cas d'usage : Mocker les services de base de donnees ou les APIs externes dans les tests d'integration.
Pattern pour retourner les resultats par pages via offset/limit ou cursor-based. Evite de charger des milliers d'enregistrements en une seule requete.
Comme un livre avec des pages : tu lis page par page au lieu de tout le livre d'un coup.
async findAll(page = 1, limit = 10) {
const [items, total] = await this.repo.findAndCount({
skip: (page - 1) * limit,
take: limit,
});
return { items, total, page, lastPage: Math.ceil(total / limit) };
}Cas d'usage : Toute API de liste doit etre paginee pour eviter les reponses massives et les timeouts.
Librairie d'authentification integree via @nestjs/passport. Fournit un systeme de strategies (JWT, Local, OAuth2) avec des guards dedies.
Comme un systeme de verification d'identite multi-documents : passeport, carte d'identite ou badge selon le contexte.
@Injectable()
export class JwtAuthGuard extends AuthGuard('jwt') {}
@Controller('profile')
export class ProfileController {
@UseGuards(JwtAuthGuard)
@Get()
getProfile(@Request() req) { return req.user; }
}Cas d'usage : Implementer l'authentification avec support multi-strategies dans une API NestJS.
Classe implementant PipeTransform qui valide ou transforme les donnees entrantes avant qu'elles atteignent le handler. Fonctionne avec class-validator.
Comme un filtre a eau : l'eau (donnees) passe a travers et seule l'eau propre (valide) continue.
@Injectable()
export class ParseIntPipe implements PipeTransform {
transform(value: string): number {
const val = parseInt(value, 10);
if (isNaN(val)) throw new BadRequestException('Not a number');
return val;
}
}Cas d'usage : Valider les DTOs entrants avec class-validator ou transformer les parametres de route.
Methode de Prisma Client pour executer plusieurs operations en transaction atomique. Supporte le mode batch (tableau) et le mode interactif (callback).
Comme un contrat notarie : toutes les clauses s'appliquent ensemble ou le contrat est annule.
await this.prisma.$transaction(async (tx) => {
const user = await tx.user.create({ data: userData });
await tx.account.create({
data: { userId: user.id, balance: 0 },
});
});Cas d'usage : Garantir l'atomicite lors de la creation d'entites liees comme user + compte.
Client auto-genere et type-safe pour interagir avec la base de donnees. Fournit une API fluide avec autocompletion complete en TypeScript.
Comme un assistant personnel qui connait parfaitement ta base de donnees et te corrige en temps reel.
@Injectable()
export class UserService {
constructor(private prisma: PrismaService) {}
findAll() {
return this.prisma.user.findMany({
include: { posts: true },
});
}
}Cas d'usage : Effectuer des requetes type-safe avec autocompletion et validation au compile-time.
Systeme de migration genere automatiquement a partir des changements du schema Prisma. Cree des fichiers SQL versiones pour chaque modification.
Comme un photographe qui capture chaque modification de la maison pour pouvoir les rejouer ou annuler.
// Terminal
// npx prisma migrate dev --name add-user-role
// Genere: migrations/20240101_add_user_role/migration.sql
// ALTER TABLE "User" ADD COLUMN "role" TEXT DEFAULT 'user';Cas d'usage : Versionner et deployer les changements de schema en production avec Prisma.
Fichier schema.prisma qui definit les modeles, relations et source de donnees en SDL (Schema Definition Language). Genere le client type-safe.
Comme un plan de construction : tu dessines la structure et Prisma genere toute la plomberie automatiquement.
// schema.prisma
model User {
id Int @id @default(autoincrement())
email String @unique
name String?
posts Post[]
}
model Post {
id Int @id @default(autoincrement())
author User @relation(fields: [authorId], references: [id])
authorId Int
}Cas d'usage : Definir le schema de donnees de facon declarative et generer un client ORM type-safe.
Toute classe injectable dans le systeme DI de NestJS via @Injectable. Les services, repositories, factories et helpers sont tous des providers.
Comme un artisan dans une cooperative : il offre ses competences et peut etre appele par quiconque en a besoin.
@Injectable()
export class LoggerService {
log(message: string) {
console.log(`[LOG] ${message}`);
}
}Cas d'usage : Encapsuler la logique metier, l'acces aux donnees ou tout service reutilisable dans l'application.
Mecanisme qui limite le nombre de requetes par client dans une fenetre de temps. Implementable via @nestjs/throttler pour proteger contre les abus.
Comme un portillon de metro : il ne laisse passer qu'un certain nombre de personnes par minute.
@Module({
imports: [ThrottlerModule.forRoot([{
ttl: 60000,
limit: 10,
}])],
})
export class AppModule {}
@UseGuards(ThrottlerGuard)
@Controller('auth')
export class AuthController {}Cas d'usage : Proteger les endpoints de login ou d'API publique contre le brute force et les abus.
Role-Based Access Control : systeme d'autorisation ou les permissions sont attribuees a des roles (admin, user, editor) plutot qu'a des individus.
Comme les cles d'un immeuble : le gardien a le passe-partout, les residents ont la cle de leur etage.
@Injectable()
export class RolesGuard implements CanActivate {
constructor(private reflector: Reflector) {}
canActivate(ctx: ExecutionContext) {
const roles = this.reflector.get<string[]>('roles', ctx.getHandler());
if (!roles) return true;
const user = ctx.switchToHttp().getRequest().user;
return roles.includes(user.role);
}
}Cas d'usage : Restreindre l'acces aux endpoints admin ou moderateur selon le role de l'utilisateur.
Data Transfer Object : classe qui definit la structure des donnees entrantes/sortantes. Utilisee avec class-validator pour la validation automatique.
Comme un formulaire officiel : il definit les champs attendus et rejette les soumissions invalides.
export class CreateUserDto {
@IsEmail()
email: string;
@IsString()
@MinLength(8)
password: string;
@IsOptional()
@IsString()
name?: string;
}Cas d'usage : Valider et typer les donnees entrantes de l'API avant qu'elles atteignent la logique metier.
Module pour planifier des taches periodiques via des decorateurs cron (@Cron), interval (@Interval) ou timeout (@Timeout).
Comme un reveil programme : il execute automatiquement des actions a des heures definies.
@Injectable()
export class TaskService {
@Cron('0 0 * * *') // Chaque jour a minuit
async dailyCleanup() {
await this.sessionService.deleteExpired();
}
@Interval(30000) // Toutes les 30 secondes
checkHealth() { this.logger.log('Health check'); }
}Cas d'usage : Executer des taches de maintenance comme le nettoyage de sessions expirees ou l'envoi de rapports.
Processus de remplissage de la base de donnees avec des donnees initiales ou de test. Execute via des scripts ou des modules dedies au demarrage.
Comme meubler un appartement temoin : tu prepares des donnees de demo pour que tout soit fonctionnel.
@Injectable()
export class SeedService implements OnModuleInit {
constructor(private userService: UserService) {}
async onModuleInit() {
const count = await this.userService.count();
if (count === 0) {
await this.userService.create({ email: 'admin@app.com', role: 'admin' });
}
}
}Cas d'usage : Initialiser les roles, permissions ou comptes admin lors du premier deploiement.
Transformation des objets en reponse JSON via ClassSerializerInterceptor et class-transformer. Permet d'exclure des champs sensibles avec @Exclude.
Comme un filtre photo qui masque les informations sensibles avant de publier.
export class UserEntity {
id: number;
email: string;
@Exclude()
password: string;
constructor(partial: Partial<UserEntity>) {
Object.assign(this, partial);
}
}Cas d'usage : Masquer les mots de passe, tokens internes et donnees sensibles des reponses API.
Provider dedie a la logique metier, annote @Injectable. Il encapsule les operations de domaine et est injecte dans les controllers ou autres services.
Comme le chef cuisinier d'un restaurant : le serveur (controller) prend la commande mais c'est le chef qui cuisine.
@Injectable()
export class UserService {
constructor(private repo: UserRepository) {}
async findAll(): Promise<User[]> {
return this.repo.find();
}
}Cas d'usage : Centraliser la logique metier pour qu'elle soit testable independamment des controllers.
Server-Sent Events : protocole HTTP unidirectionnel du serveur vers le client. Plus simple que WebSocket quand le flux est unidirectionnel.
Comme une radio : le serveur diffuse et les clients ecoutent, sans possibilite de repondre via le meme canal.
@Controller('events')
export class EventController {
@Sse('stream')
stream(): Observable<MessageEvent> {
return interval(1000).pipe(
map(i => ({ data: { count: i } } as MessageEvent)),
);
}
}Cas d'usage : Streamer des mises a jour de progression, logs temps reel ou notifications sans WebSocket.
Module @nestjs/swagger qui genere automatiquement la documentation API OpenAPI a partir des decorateurs, DTOs et controllers.
Comme un menu de restaurant genere automatiquement a partir des plats disponibles en cuisine.
const config = new DocumentBuilder()
.setTitle('My API')
.setVersion('1.0')
.addBearerAuth()
.build();
const doc = SwaggerModule.createDocument(app, config);
SwaggerModule.setup('api', app, doc);Cas d'usage : Fournir une documentation API interactive et toujours a jour pour les developpeurs frontend.
Module de health checks via @nestjs/terminus. Expose un endpoint /health qui verifie la base de donnees, Redis, disque et services externes.
Comme un bilan de sante : le medecin verifie chaque organe et donne un bulletin de sante global.
@Controller('health')
export class HealthController {
constructor(private health: HealthCheckService,
private db: TypeOrmHealthIndicator) {}
@Get()
check() {
return this.health.check([
() => this.db.pingCheck('database'),
]);
}
}Cas d'usage : Fournir un endpoint de sante pour les load balancers et orchestrateurs comme Kubernetes.
Couche d'abstraction de NestJS pour la communication entre microservices. Supporte TCP, Redis, NATS, MQTT, RabbitMQ, Kafka et gRPC.
Comme choisir entre la poste, le coursier ou le mail : le message est le meme, seul le moyen de transport change.
// main.ts
const app = await NestFactory.createMicroservice(AppModule, {
transport: Transport.REDIS,
options: { host: 'localhost', port: 6379 },
});
await app.listen();Cas d'usage : Connecter des microservices NestJS via differents brokers de messages selon les besoins.
Classe decoree @Entity qui represente une table de base de donnees. Chaque propriete decoree (@Column, @PrimaryGeneratedColumn) correspond a une colonne.
Comme un plan d'architecte : il decrit la structure exacte de la table a construire.
@Entity()
export class User {
@PrimaryGeneratedColumn()
id: number;
@Column({ unique: true })
email: string;
@Column({ default: true })
isActive: boolean;
}Cas d'usage : Definir le schema de la base de donnees directement dans le code TypeScript avec TypeORM.
Fichier versionne qui decrit les modifications de schema de base de donnees (up/down). Permet de gerer l'evolution du schema de facon reproductible.
Comme un historique Git mais pour la structure de ta base de donnees.
export class AddUserAge1234567890 implements MigrationInterface {
async up(qr: QueryRunner) {
await qr.addColumn('user',
new TableColumn({ name: 'age', type: 'int', isNullable: true }));
}
async down(qr: QueryRunner) {
await qr.dropColumn('user', 'age');
}
}Cas d'usage : Deployer des changements de schema en production de maniere securisee et reversible.
API fluide pour construire des requetes SQL complexes avec TypeORM. Supporte les jointures, sous-requetes, groupements et requetes paginee.
Comme assembler une requete en Lego : tu ajoutes chaque piece (clause) une par une pour construire la requete finale.
const users = await this.repo
.createQueryBuilder('user')
.leftJoinAndSelect('user.orders', 'order')
.where('user.isActive = :active', { active: true })
.orderBy('user.createdAt', 'DESC')
.take(10)
.getMany();Cas d'usage : Construire des requetes complexes avec jointures, filtres dynamiques et pagination.
Decorateurs (@OneToMany, @ManyToOne, @ManyToMany, @OneToOne) qui definissent les relations entre entites. Permettent le chargement eager ou lazy.
Comme les liens de parente dans un arbre genealogique : chaque relation a un type et une direction.
@Entity()
export class User {
@OneToMany(() => Order, order => order.user)
orders: Order[];
}
@Entity()
export class Order {
@ManyToOne(() => User, user => user.orders)
user: User;
}Cas d'usage : Modeliser les associations entre tables et naviguer le graphe d'objets en TypeScript.
Pattern d'acces aux donnees qui fournit des methodes CRUD (find, save, delete) pour une entite. Injecte via @InjectRepository dans les services.
Comme un bibliothecaire specialise : il sait exactement comment chercher, ranger et preter les livres de sa section.
@Injectable()
export class UserService {
constructor(
@InjectRepository(User)
private repo: Repository<User>,
) {}
findAll() { return this.repo.find(); }
}Cas d'usage : Effectuer les operations CRUD sur les entites sans ecrire de SQL brut.
Mecanisme pour executer plusieurs operations de base de donnees de facon atomique. Soit toutes reussissent, soit toutes sont annulees.
Comme un virement bancaire : le debit ET le credit doivent passer ensemble, sinon rien ne bouge.
async transfer(from: string, to: string, amount: number) {
await this.dataSource.transaction(async (manager) => {
await manager.decrement(Account, { id: from }, 'balance', amount);
await manager.increment(Account, { id: to }, 'balance', amount);
});
}Cas d'usage : Garantir la coherence des donnees lors d'operations multi-tables comme les paiements.
Systeme de versioning d'API integre supportant URI (/v1/), header, media type et custom. Permet d'evoluer l'API sans casser les clients existants.
Comme les editions d'un livre : la v2 existe mais la v1 reste disponible pour ceux qui l'utilisent.
app.enableVersioning({ type: VersioningType.URI });
@Controller({ path: 'users', version: '1' })
export class UserV1Controller {}
@Controller({ path: 'users', version: '2' })
export class UserV2Controller {}Cas d'usage : Maintenir la retrocompatibilite tout en deployant de nouvelles versions d'endpoints.
Classe decoree @WebSocketGateway qui gere les connexions WebSocket bidirectionnelles. Utilise Socket.IO ou ws pour la communication temps reel.
Comme un talkie-walkie : la communication est instantanee dans les deux sens, sans besoin de 'rappeler'.
@WebSocketGateway({ cors: true })
export class ChatGateway {
@WebSocketServer() server: Server;
@SubscribeMessage('message')
handleMessage(@MessageBody() data: string) {
this.server.emit('message', data);
}
}Cas d'usage : Implementer un chat en temps reel, des notifications push ou un tableau de bord live.
Autres stacks