Nestjs
Senior
Quiz-Nestjs-Senior
Nestjs-Microservices
Websockets
Performance-Nestjs
Nestjs-Securite
Architecture-Hexagonale
Questions-Entretien-Nestjs-Senior
Qcm-Nestjs-Avance
Patterns-Nestjs
Graphql
Node-Js
Back-End
📝
NestJS Senior — Microservices & WS
20 questions avancées NestJS : microservices, WebSockets, performance, sécurité, architecture hexagonale et patterns professionnels. Idéal pour réussir un entretien NestJS Senior.
Banque de révision : les 30 questions corrigées
Voici l'intégralité des 30 questions de « NestJS Senior — Microservices & WS », chacune avec sa bonne réponse et son explication. Le quiz interactif ci-dessus en tire une sélection aléatoire à chaque tentative — utilisez cette liste complète pour réviser.
Explication :
Un provider avec
useFactory peut être async. NestJS attendra la résolution de la Promesse avant de rendre le provider disponible. Les dépendances listées dans deps sont injectées avant l'exécution de la factory.
Exemple :
{ provide: "DB", useFactory: async (config) => { await connect(config); return db; }, inject: [ConfigService] }
Explication :
Le graceful shutdown permet de fermer proprement les connexions, terminer les requêtes en cours, puis arrêter l'application. On active
app.enableShutdownHooks(), on implémente OnApplicationShutdown dans les services, et on écoute SIGTERM (Kubernetes) et SIGINT (Ctrl+C).
En Kubernetes, le preStop hook peut aussi être utilisé. Timeout recommandé : 30 secondes pour terminer les requêtes.
Explication :
NestJS supporte nativement TCP, Redis, NATS, MQTT, gRPC, Kafka, RabbitMQ. Un custom transport permet d'ajouter son propre protocole (WebSocket personnalisé, AMQP, etc.). On implémente
CustomTransportStrategy et on l'utilise avec @MessagePattern().
Exemple : transporter via WebRTC, WebSocket brut, ou un bus personnalisé.
Explication :
Le
ModuleRef donne accès au conteneur d'injection. get(Provider) récupère une instance (singleton). resolve(Provider) crée une nouvelle instance (scope transient). Utile pour les providers non injectés dans le constructeur ou les usines dynamiques.
Attention :
resolve() peut créer des fuites mémoire si utilisé sans contextId. Utilisez registerRequestByContextId() pour le scope REQUEST.
Explication :
NestJS permet de remplacer le logger par défaut. On peut créer un service implémentant
LoggerService ou utiliser Winston/Pino. Exemple : app.useLogger(new WinstonLogger()). Les transports peuvent être console, fichier, Elasticsearch, Datadog, etc.
En production, utilisez des logs structurés (JSON) pour faciliter l'intégration avec des outils comme ELK ou Loki.
Explication :
Le
ExecutionContext (hérité de ArgumentsHost) donne accès au contexte : switchToHttp() pour HTTP, switchToRpc() pour microservices, switchToWs() pour WebSocket. On peut aussi obtenir le handler et la classe pour lire les métadonnées avec Reflector.
Utile pour créer des guards génériques qui s'adaptent au type de transport (HTTP, RPC, WebSocket).
Explication :
Une application hybride combine un serveur HTTP (Express/Fastify) avec des microservices (TCP, Redis, etc.) et des WebSocket. On utilise
app.connectMicroservice() pour chaque microservice, puis app.startAllMicroservices() et app.listen().
Exemple : serveur HTTP pour l'API REST + microservice TCP pour la communication interne + Gateway WebSocket pour le temps réel.
Explication :
Le scope contrôle la durée de vie :
DEFAULT (singleton global), REQUEST (instance par requête HTTP, utile pour stocker l'utilisateur courant), TRANSIENT (nouvelle instance à chaque injection). Le scope REQUEST a un coût en performance et nécessite ContextIdFactory pour le partage entre services.
Pour le scope REQUEST, utilisez
@Injectable({ scope: Scope.REQUEST }) et @Inject(REQUEST) pour accéder à l'objet requête.
Explication :
@nestjs/throttler supporte Redis store pour le rate limiting distribué (plusieurs instances). On peut aussi implémenter un guard personnalisé avec Redis et un algorithme (token bucket, sliding window, fixed window) pour plus de contrôle.
Algorithme sliding window (plus précis) : stocker les timestamps dans un Redis Sorted Set avec expiration. Token bucket : incrémenter/décrémenter un compteur Redis.
Explication :
Pattern :
@Roles("admin") définit des métadonnées via @SetMetadata(). Un guard lit ces métadonnées avec Reflector.get() et ExecutionContext, puis compare avec le rôle de l'utilisateur extrait du token JWT.
Combinaison puissante : AuthGuard (authentification) + RolesGuard (autorisation). Permet une sécurité déclarative fine.
Explication :
Le tracing distribué nécessite de propager un contexte (traceId, parentSpanId) entre services. Dans NestJS, on crée un interceptor qui génère/gère les spans, et un transporteur qui propage les headers (ex: avec Redis, Kafka, gRPC metadata). On exporte vers Jaeger/Zipkin via OpenTelemetry.
Utilisez
@opentelemetry/instrumentation-nestjs-core pour l'instrumentation automatique. Propager les headers via RpcException ou metadata.
Explication :
L'idempotence pour POST permet d'éviter les doublons (ex: paiement). L'interceptor lit le header
Idempotency-Key, vérifie dans Redis si la clé existe. Si oui, retourne la réponse précédente (cachée). Si non, exécute la requête, stocke le résultat avec TTL, et retourne.
Stockez la réponse complète (200, 201, 400, 422). TTL typique : 24h. Gérez le nettoyage automatique avec Redis TTL.
Explication :
NestJS permet d'utiliser des intercepteurs sur les méthodes
@GrpcMethod(). On peut mesurer le temps, logger les requêtes/réponses, capturer les erreurs, et exporter des métriques Prometheus. Le contexte est différent du HTTP (RpcContext).
Pour gRPC, l'interceptor reçoit un
RpcContext qui donne accès aux metadata gRPC (trailers, headers).
Explication :
Le module
@nestjs/cqrs fournit : @CommandHandler (mutation), @QueryHandler (lecture), @EventsHandler (réactions asynchrones), Saga (orchestration). Séparation du modèle de lecture (lecture simple) et d'écriture (validation, logique métier).
CQRS est adapté aux domaines complexes (commandes, e-commerce, finance). Pour les CRUD simples, l'architecture standard suffit.
Explication :
Les intercepteurs peuvent être REQUEST scoped (
@Injectable({ scope: Scope.REQUEST })). Ils peuvent alors injecter des providers REQUEST scoped. Cependant, cela crée une nouvelle instance d'intercepteur par requête, ce qui peut dégrader les performances.
Préférez des intercepteurs singleton (DEFAULT) et passez les données via le contexte (ExecutionContext) plutôt que via des providers REQUEST scoped.
Explication :
L'event sourcing stocke tous les événements passés, permettant d'auditer, de rejouer, ou de corriger l'état. NestJS avec
@nestjs/cqrs gère les événements. L'intégration avec EventStoreDB (ou Kafka) nécessite un custom EventPublisher et EventBus.
Combine CQRS + Event Sourcing : les commands produisent des événements, les queries lisent les projections (vues matérialisées).
Explication :
Pour Lambda : 1) Mode standalone (sans serveur HTTP) :
NestFactory.createApplicationContext(). 2) Réduire le bundle avec esbuild (plus rapide que webpack). 3) Lazy loading des modules lourds. 4) Utiliser la provisioned concurrency d'AWS. 5) Optimiser les dépendances.
Le standalone mode est plus léger car il n'initialise pas le serveur HTTP (Express/Fastify). Utilisez
@nestjs/axios pour les requêtes HTTP sortantes.
Explication :
Le module
@nestjs/cache-manager supporte différents stores. Pour Redis Cluster, on configure cacheManager.registerStore avec ioredis (cluster). Les caches sont alors partagés entre toutes les instances de l'application.
Exemple de décorateur :
@CacheKey("users") @CacheTTL(60) async getUsers(). Utilisez des TTL différents selon la volatilité des données.
Explication :
Un exception filter personnalisé capture toutes les exceptions (
catch(exception, host)) et transforme la réponse. On peut implémenter JSON:API (errors object), RFC 7807 (Problem Details), ou un format maison. Utile pour la cohérence entre microservices.
Exemple de format standardisé :
{ "type": "/errors/validation", "title": "Validation Failed", "status": 422, "details": [ ... ] }
Explication :
Pattern de retry avec backoff : échec → attendre 1s → réessayer → échec → attendre 2s → etc. Avec RxJS :
retryWhen(errors => errors.pipe(delayWhen(() => timer(backoff)))). On peut ajouter du jitter (variation aléatoire) pour éviter l'effet de meute.
Backoff exponentiel avec jitter : 100ms, 200ms, 400ms, 800ms... Maximum 10 retries. Idempotence importante pour les retries.
Explication :
Un module dynamique (
forRootAsync) permet de configurer le module avec des options asynchrones (DB, API). Exemple : TypeOrmModule.forRootAsync({ useFactory: (config) => config.get("db"), inject: [ConfigService] }). Utile quand la config vient d'un service.
Pattern :
registerAsync et forRootAsync. Utilisez useFactory, useClass, ou useExisting pour fournir les options.
Explication :
Pour propager le contexte (traceId, userId) entre microservices : 1) Client side : ajouter des metadata/headers. 2) Server side : extraire les metadata dans un interceptor et les stocker dans le contexte (AsyncLocalStorage). Tous les services peuvent alors accéder au contexte.
AsyncLocalStorage (Node.js natif) ou
cls-hooked pour maintenir le contexte à travers les appels asynchrones.
Explication :
Le circuit breaker évite les appels inutiles à un service défaillant. États : CLOSED (appels normaux), OPEN (rejet immédiat, fail fast), HALF-OPEN (test après timeout). On peut utiliser une lib comme
opossum ou implémenter avec un interceptor et Redis (distribué).
Combinez circuit breaker + retry + timeout + fallback (cache, réponse par défaut). Pattern "Resilience4j" en Java.
Explication :
Un custom param decorator extrait l'utilisateur du token JWT (ajouté par AuthGuard) et le retourne typé. Exemple :
@CurrentUser() user: UserDto. On peut aussi passer des paramètres (ex: @CurrentUser("id") userId: string).
Le decorator peut être générique :
@CurrentUser() user: T. On peut aussi y ajouter des validations.
Explication :
GraphQL Federation permet de composer plusieurs services GraphQL en un seul graphe. Dans NestJS, on utilise
@ResolveReference() pour implémenter l'entité fédérée. Le service expose son schéma, Apollo Gateway les agrège.
Décorateurs :
@EntityReference(), @ResolveReference(). Le gateway doit être configuré avec les URLs des sous-graphes.
Explication :
On peut créer des validateurs asynchrones avec
@ValidatorConstraint({ async: true }). Pour injecter un service (ex: UserService), on utilise ValidationArguments ou un module global avec setContainer (class-validator).
Exemple :
@IsEmailUnique() qui vérifie en base que l'email n'existe pas. Nécessite class-validator@0.14+.
Explication :
Le standalone mode (
NestFactory.createApplicationContext()) crée une application NestJS sans serveur HTTP. Tous les modules, services, et l'injection de dépendances fonctionnent. Idéal pour : scripts CLI, workers background, cron jobs, consommateurs Kafka.
Exemple : script de seeding de base de données, import CSV, envoi d'emails batch. Fermez proprement avec
app.close().
Explication :
Le
ClassSerializerInterceptor utilise class-transformer pour sérialiser les objets. On peut exclure des propriétés (@Exclude()), exposer (@Expose()), ou grouper (@Groups(["admin"])) pour des contextes différents.
Activation :
@UseInterceptors(ClassSerializerInterceptor) sur le contrôleur. Transforme aussi les dates (@Type(() => Date)).
Explication :
Approches : 1) Interceptor HTTP + service d'audit (enregistre qui a fait quoi, avant/après). 2) Subscriber TypeORM (
@EventSubscriber()) qui capture les changements au niveau ORM. 3) Triggers PostgreSQL avec table d'audit (plus bas niveau).
Audit log minimal : userId, action, table, ancienne_valeur, nouvelle_valeur, timestamp. Pour la GDPR, permettre l'export des logs par utilisateur.
Explication :
NestJS a un transport Kafka intégré. On peut configurer
consumer: { groupId: "my-group" }. La reprise après échec : commit: false pour commit manuel après traitement réussi. Les partitions sont gérées automatiquement (rééquilibrage).
Pattern dead letter queue : consommer les messages invalides vers un topic DLQ. Gérer le rejeu des messages avec des offsets personnalisés.