Desarrollo e inyección de servicios

Intermedio
Nest
Nest
Actualizado: 09/06/2025

¡Desbloquea el curso completo!

IA
Ejercicios
Certificado
Entrar

La inyección de dependencias es un patrón de diseño fundamental en el desarrollo de software que permite a una clase obtener las dependencias que necesita desde fuentes externas, en lugar de crearlas por sí misma. NestJS, al ser un framework para la creación de aplicaciones de servidor con Node.js, utiliza este patrón de manera intensiva, principalmente a través de su sistema de módulos y proveedores.

¿Qué es un servicio?

Un servicio es una clase que se utiliza para organizar la lógica de negocio de una aplicación. Realizan tareas especificas como:

  • Interactuar con bases de datos.
  • Realizar llamadas a APIs externas.
  • Ejecutar cálculos complejos.
  • Cualquier otra tarea que no deba realizarse directamente en los controladores.

Los servicios son altamente reutilizables y se pueden inyectar en controladores, otros servicios o cualquier componente que necesite utilizar su funcionalidad.

Ejemplo de un servicio simple:

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

@Injectable()
export class AppService {
  getHello(): string {
    return '¡Hola Mundo!';
  }
}

¿Qué significa @Injectable?

La anotación @Injectable() es un decorador proporcionado por NestJS. Indica que la clase puede ser administrada por el sistema de inyección de dependencias de NestJS.

En otras palabras, una vez que una clase tiene este decorador, puede ser inyectada como dependencia en otro componente.

Inyectando un servicio

Para inyectar un servicio, simplemente se debe declarar en el constructor del componente en el que se desee utilizar. NestJS se encargará automáticamente de instanciar y proporcionar el servicio.

Es crucial que el parámetro del constructor esté tipado con la clase del servicio (AppService en este caso). NestJS utiliza este tipo para identificar y resolver la dependencia correcta.

Ejemplo:

Suponiendo que se tiene el servicio AppService del ejemplo anterior y se desea inyectar en un controlador:

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

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

  @Get()
  getHello(): string {
    return this.appService.getHello();
  }
}

En el código anterior, AppService es inyectado en AppController a través del constructor. Ahora, el método getHello() del servicio está disponible para ser utilizado en el controlador.

Proveedores

Los proveedores son componentes fundamentales en NestJS que encapsulan y proporcionan funcionalidades o servicios a otras partes de la aplicación.

Los servicios son un tipo específico de proveedor que se utiliza comúnmente para manejar la lógica de negocio y acceder a datos.

Los proveedores y servicios se pueden inyectar en otros componentes, como controladores y otros proveedores, mediante la inyección de dependencias.

Sin embargo, un proveedor puede ser cualquier valor, clase, servicio o función que se desea que esté disponible para ser inyectado en otros componentes.

Beneficios de la inyección de dependencias

  • Desacoplamiento: Los componentes no necesitan conocer detalles específicos sobre cómo se crean o gestionan sus dependencias. Esto los hace más independientes.
  • Reutilización: Los servicios (y otros proveedores) se pueden reutilizar fácilmente en diferentes partes de la aplicación, promoviendo un código más limpio y eficiente.
  • Testabilidad: Facilita enormemente la escritura de pruebas unitarias, ya que las dependencias pueden ser fácilmente simuladas (mocked) o reemplazadas durante los tests.

Registro de proveedores

Para que un servicio pueda ser inyectado, primero debe ser registrado como proveedor en un módulo. NestJS utiliza módulos para organizar partes relacionadas de la aplicación.

Guarda tu progreso

Inicia sesión para no perder tu progreso y accede a miles de tutoriales, ejercicios prácticos y nuestro asistente de IA.

Progreso guardado
Asistente IA
Ejercicios
Iniciar sesión gratis

Más de 25.000 desarrolladores ya confían en CertiDevs

Cuando se registra un servicio como proveedor, este se hace disponible para ser inyectado en cualquier componente que pertenezca al mismo módulo o en módulos que importen el módulo en el que se encuentra registrado.

Ejemplo de registro de AppService en un módulo:

import { Module } from '@nestjs/common';
import { AppController } from './app.controller';
import { AppService } from './app.service';

@Module({
  imports: [],
  controllers: [AppController],
  providers: [AppService], // <-- Aquí se registra AppService como proveedor
})
export class AppModule {}

En el fragmento anterior, AppService se registra como proveedor en AppModule. Esto significa que cualquier componente dentro de AppModule puede tener AppService inyectado a través de su constructor.

Exportación de servicios

En algunos casos, se puede necesitar que un servicio esté disponible para ser inyectado en otros módulos. Para esto, se puede utilizar la propiedad exports del decorador @Module().

Por ejemplo, supongamos que en un módulo llamado MiModulo se busca que el servicio MiServicio sea accesible tanto dentro como fuera de MiModulo, el código podría verse de la siguiente manera:

import { Module } from '@nestjs/common';
import { MiServicio } from './mi-servicio.service'; // Asegúrate de que la ruta sea correcta

@Module({
  providers: [MiServicio], // Registra el servicio en providers
  exports: [MiServicio],   // Exporta el servicio para que sea accesible desde otros módulos
})
export class MiModulo {}

Inyección de dependencias personalizadas

NestJS ofrece la capacidad de definir proveedores personalizados, lo que te permite un mayor control sobre cómo se resuelven las dependencias. Esto es útil para inyectar configuraciones, valores específicos o implementaciones alternativas de interfaces.

Aquí los tipos más comunes de proveedores personalizados:

  • useFactory: Para proveer un valor que se genera a partir de una función.
const connectionFactory = {
  provide: 'CONNECTION', // Token de inyección
  useFactory: () => {
    // Lógica para crear y devolver la conexión
    return { message: 'Conexión a la base de datos simulada' };
  },
};

@Module({
  providers: [connectionFactory],
})
export class DatabaseModule {}

Para usarlo, inyectarías @Inject('CONNECTION') connection: any.

  • useClass: Para proveer una implementación específica de una clase, útil para cambiar el comportamiento de un servicio sin modificar el código que lo usa.
interface IMailService {
  sendMail(to: string, subject: string, body: string): Promise<void>;
}

class SendGridMailService implements IMailService {
  async sendMail(to: string, subject: string, body: string) {
    console.log(`Sending email via SendGrid to ${to}: ${subject}`);
  }
}

// En el módulo
@Module({
  providers: [{
    provide: 'MAIL_SERVICE', // Token de inyección
    useClass: SendGridMailService, // Usa esta clase como implementación
  }],
  exports: ['MAIL_SERVICE']
})
export class MailModule {}
  • useValue: Para proveer un valor estático, un objeto pre-existente o una constante.
const API_KEY_VALUE = 'mi-clave-secreta-12345';

@Module({
  providers: [{
    provide: 'API_KEY', // Token de inyección
    useValue: API_KEY_VALUE, // Inyecta este valor directamente
  }],
  exports: ['API_KEY']
})
export class ConfigModule {}

Para usarlo, inyectarías @Inject('API_KEY') apiKey: string.

Ámbito de proveedores

Por defecto, los proveedores en NestJS son singleton, es decir, se crea una única instancia que es compartida entre todos los consumidores en toda la aplicación. Sin embargo, en algunos casos se podría necesitar que cada consumidor reciba una nueva instancia del proveedor.

NestJS ofrece diferentes ámbitos para los proveedores:

  • Scope.DEFAULT (Singleton): (Por defecto) Una única instancia compartida globalmente.
  • Scope.REQUEST: Se crea una nueva instancia del proveedor por cada petición HTTP. Útil para información ligada al ciclo de vida de una petición.
  • Scope.TRANSIENT: Se crea una nueva instancia cada vez que se solicita el proveedor.

Ejemplo de un proveedor transitorio:

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

@Injectable({ scope: Scope.TRANSIENT }) // Este servicio tendrá una nueva instancia cada vez que se inyecte
export class TransientService {
  private id: number;
  constructor() {
    this.id = Math.random(); // Demuestra que cada instancia es única
    console.log(`TransientService instancia creada: ${this.id}`);
  }

  getId(): number {
    return this.id;
  }
}

Inyección Opcional con @Optional()

En ocasiones, un proveedor puede no ser estrictamente necesario para el funcionamiento de un componente. En estos casos, puedes usar el decorador **@Optional()** junto con @Inject() (o el tipado del constructor) para indicar que la dependencia es opcional. Si NestJS no puede resolver el proveedor, en lugar de lanzar un error, inyectará undefined.

import { Controller, Get, Optional, Inject } from '@nestjs/common';
import { SomeOptionalService } from './some-optional.service';

@Controller()
export class MyController {
  constructor(@Optional() @Inject(SomeOptionalService) private readonly optionalService: SomeOptionalService) {}

  @Get('check-optional')
  checkOptional(): string {
    if (this.optionalService) {
      return `OptionalService está disponible: ${this.optionalService.doSomething()}`;
    }
    return 'OptionalService no está disponible.';
  }
}

Conclusión

La inyección de servicios y dependencias es un pilar fundamental en NestJS. Permite construir una arquitectura desacoplada, modular y altamente testable, facilitando el mantenimiento y la escalabilidad de tus aplicaciones. Al dominar este mecanismo, tendrás una base sólida para desarrollar aplicaciones robustas y eficientes con NestJS.

Aprendizajes de esta lección

  • Comprender el concepto de servicio en NestJS.
  • Saber qué significa el decorador @Injectable.
  • Conocer cómo inyectar un servicio.
  • Diferenciar entre servicios y proveedores.
  • Entender los beneficios de la inyección de dependencias en NestJS.

Completa Nest y certifícate

Únete a nuestra plataforma y accede a miles de tutoriales, ejercicios prácticos, proyectos reales y nuestro asistente de IA personalizado para acelerar tu aprendizaje.

Asistente IA

Resuelve dudas al instante

Ejercicios

Practica con proyectos reales

Certificados

Valida tus conocimientos

Más de 25.000 desarrolladores ya se han certificado con CertiDevs

⭐⭐⭐⭐⭐
4.9/5 valoración