37. Inyección de dependencias

Inyección de Dependencias en NestJS: Explicación Práctica con Ejemplo

La inyección de dependencias (DI) es un patrón de diseño fundamental en NestJS que promueve el desacoplamiento y la reutilización de código. En este post, aprenderás cómo implementarlo paso a paso con un ejemplo práctico usando un módulo de Cars.


Estructura del Proyecto

Primero, veamos la estructura de directorios:

plaintext
Copy
Download
src/
│
├── cars/
│   ├── cars.controller.ts   # Controlador (maneja rutas HTTP)
│   ├── cars.module.ts       # Módulo (registra controlador y servicio)
│   └── cars.service.ts      # Servicio (lógica de negocio)
│
├── app.module.ts            # Módulo principal
└── main.ts                  # Punto de entrada

Paso 1: Crear el Servicio (CarsService)

El servicio contiene la lógica de negocio y se marca con el decorador @Injectable() para que NestJS lo gestione como una dependencia:

typescript
Copy
Download
import { Injectable } from '@nestjs/common';

@Injectable()
export class CarsService {
  private cars = [
    { id: 1, brand: 'Toyota', model: 'Corolla' },
    { id: 2, brand: 'Honda', model: 'Civic' },
    { id: 3, brand: 'Jeep', model: 'Cherokee' },
  ];

  findAll() {
    return this.cars;
  }

  findOneById(id: number) {
    return this.cars.find(car => car.id === id);
  }
}

Paso 2: Inyectar el Servicio en el Controlador (CarsController)

NestJS utiliza el constructor para inyectar dependencias. Aquí, CarsService se inyecta en CarsController:

typescript
Copy
Download
import { Controller, Get, Param } from '@nestjs/common';
import { CarsService } from './cars.service';

@Controller('cars')
export class CarsController {
  constructor(private readonly carsService: CarsService) {} // Inyección

  @Get()
  getAllCars() {
    return this.carsService.findAll(); // Usa el método del servicio
  }

  @Get(':id')
  getCarById(@Param('id') id: string) {
    return this.carsService.findOneById(+id); // "+id" convierte string a number
  }
 @Post()
  createCar(@Body() body: any) {
    return body;
  }

  @Patch(':id')
  updateCar(
    @Param('id', ParseIntPipe) id: number,
    @Body() body: any
  ) {
    return body;
  }

  @Delete(':id')
  deleteCar(@Param('id', ParseIntPipe) id: number) {
    return {
      method: 'delete',
      id
    };
  }

}

¿Cómo funciona la Inyección?

  1. NestJS detecta que CarsController depende de CarsService (por el tipo en el constructor).

  2. Crea una instancia única (singleton) de CarsService (o reutiliza una existente).

  3. La pasa automáticamente al controlador.


Paso 3: Registrar el Módulo (CarsModule)

El módulo vincula el controlador y el servicio:

typescript
Copy
Download
import { Module } from '@nestjs/common';
import { CarsController } from './cars.controller';
import { CarsService } from './cars.service';

@Module({
  controllers: [CarsController],
  providers: [CarsService], // Registra el servicio como proveedor
})
export class CarsModule {}

Pruebas en Postman

  • GET /cars: Devuelve todos los autos.

  • GET /cars/1: Devuelve el auto con id=1.

Si el id no existe, el servicio devuelve undefined (luego manejaremos errores con filtros de excepción).


Ventajas de la Inyección de Dependencias

✅ Código modular: Facilita el mantenimiento y testing.
✅ Reutilización: El mismo servicio puede usarse en múltiples controladores.
✅ Gestión automática: NestJS crea y libera instancias.


Conclusión

La inyección de dependencias es el corazón de NestJS. Con este ejemplo, has aprendido a:

  1. Crear un servicio inyectable.

  2. Inyectarlo en un controlador.

  3. Organizar el código en módulos.

En próximos posts, cubriremos pipes para validar datos y manejo de errores.

¿Te quedaron dudas? ¡Déjalas en los comentarios!


🔗 Código completoEnlace a repositorio (opcional)

📚 Más sobre NestJSDocumentación oficial

Comentarios

Entradas más populares de este blog

48. ValidationPipe - Class Validator y Class Transformer

32-Modulos

49. Pipes Globales - A nivel de Aplicación