Scopes de inyección de dependencias
Los scopes en NestJS determinan el ciclo de vida de las instancias de servicios y controlan cuándo y cómo se crean, mantienen y destruyen. Por defecto, NestJS utiliza el patrón singleton para todos los servicios, pero ofrece diferentes opciones de scope para casos específicos donde necesites un comportamiento diferente.
Tipos de scopes disponibles
NestJS proporciona tres tipos principales de scopes de inyección:
- DEFAULT (Singleton): Una única instancia del servicio se crea y comparte en toda la aplicación
- REQUEST: Se crea una nueva instancia para cada petición HTTP entrante
- TRANSIENT: Se crea una nueva instancia cada vez que se inyecta el servicio
Scope DEFAULT (Singleton)
El scope por defecto es el más eficiente en términos de memoria y rendimiento. Una sola instancia del servicio se mantiene durante toda la vida de la aplicación:
import { Injectable } from '@nestjs/common';
@Injectable()
export class UserService {
private users: User[] = [];
findAll(): User[] {
return this.users;
}
create(user: User): User {
this.users.push(user);
return user;
}
}
Este servicio mantiene el estado compartido entre todas las peticiones, lo que es ideal para servicios que gestionan datos globales o configuraciones.
Scope REQUEST
El scope REQUEST crea una nueva instancia del servicio para cada petición HTTP. Esto es útil cuando necesitas mantener datos específicos de cada petición:
import { Injectable, Scope } from '@nestjs/common';
@Injectable({ scope: Scope.REQUEST })
export class RequestLoggerService {
private logs: string[] = [];
addLog(message: string): void {
this.logs.push(`${new Date().toISOString()}: ${message}`);
}
getLogs(): string[] {
return this.logs;
}
}
En este ejemplo, cada petición tendrá su propia instancia del servicio con su propio array de logs, evitando que se mezclen los datos entre diferentes peticiones.
Scope TRANSIENT
El scope TRANSIENT crea una nueva instancia cada vez que el servicio se inyecta, incluso dentro de la misma petición:
import { Injectable, Scope } from '@nestjs/common';
@Injectable({ scope: Scope.TRANSIENT })
export class UniqueIdService {
private readonly id: string;
constructor() {
this.id = Math.random().toString(36).substring(7);
}
getId(): string {
return this.id;
}
}
Cada vez que este servicio se inyecte, se creará con un ID único, útil para casos donde necesitas garantizar instancias completamente independientes.
Configuración de scopes en controladores
Los controladores también pueden tener scopes, lo que afecta a todos los servicios que dependan de ellos:
import { Controller, Get, Scope } from '@nestjs/common';
@Controller({
path: 'users',
scope: Scope.REQUEST
})
export class UsersController {
constructor(
private readonly userService: UserService,
private readonly loggerService: RequestLoggerService
) {}
@Get()
findAll() {
this.loggerService.addLog('Fetching all users');
return this.userService.findAll();
}
}
Inyección de REQUEST object
Cuando utilizas scope REQUEST, puedes inyectar el objeto de petición directamente:
import { Injectable, Scope, Inject } from '@nestjs/common';
import { REQUEST } from '@nestjs/core';
import { Request } from 'express';
@Injectable({ scope: Scope.REQUEST })
export class RequestContextService {
constructor(@Inject(REQUEST) private request: Request) {}
getUserAgent(): string {
return this.request.headers['user-agent'] || 'Unknown';
}
getRequestId(): string {
return this.request.headers['x-request-id'] as string || 'no-id';
}
}
Consideraciones de rendimiento
El uso de scopes diferentes al DEFAULT tiene implicaciones importantes:
- REQUEST scope: Aumenta el uso de memoria y tiempo de procesamiento al crear nuevas instancias para cada petición
- TRANSIENT scope: Genera la mayor sobrecarga al crear instancias constantemente
- DEFAULT scope: Ofrece el mejor rendimiento pero comparte estado entre peticiones
Propagación de scopes
Cuando un servicio tiene un scope específico, todos los servicios que dependan de él heredarán automáticamente ese scope:
@Injectable({ scope: Scope.REQUEST })
export class DatabaseConnectionService {
// Servicio con scope REQUEST
}
@Injectable() // Automáticamente se convierte en REQUEST scope
export class UserRepository {
constructor(
private dbConnection: DatabaseConnectionService
) {}
}
Esta propagación automática garantiza la consistencia en el ciclo de vida de las dependencias relacionadas.
Fuentes y referencias
Documentación oficial y recursos externos para profundizar en Nest
Documentación oficial de Nest
Alan Sastre
Ingeniero de Software y formador, CEO en CertiDevs
Ingeniero de software especializado en Full Stack y en Inteligencia Artificial. Como CEO de CertiDevs, Nest es una de sus áreas de expertise. Con más de 15 años programando, 6K seguidores en LinkedIn y experiencia como formador, Alan se dedica a crear contenido educativo de calidad para desarrolladores de todos los niveles.
Más tutoriales de Nest
Explora más contenido relacionado con Nest y continúa aprendiendo con nuestros tutoriales gratuitos.
Aprendizajes de esta lección
- Comprender qué son los scopes en la inyección de dependencias en NestJS.
- Identificar y diferenciar los tres tipos principales de scopes: DEFAULT (singleton), REQUEST y TRANSIENT.
- Saber cómo configurar scopes en servicios y controladores.
- Entender las implicaciones de rendimiento de cada tipo de scope.
- Conocer la propagación automática de scopes entre servicios dependientes.