DEV Community

Cover image for Lo Mejor De NestJS
disced
disced

Posted on

Lo Mejor De NestJS

Índice

  1. ¿Por qué me gusta NestJS para el desarrollo backend con TypeScript?
  2. Módulos en NestJS
    1. Controladores
    2. Servicios
    3. Datos (Repositorios)
    4. Resumen
  3. Inyección de Dependencias
    1. @Injectable
    2. Inyección en el constructor
    3. Inyección en propiedades
  4. Documentación oficial Módulos NestJS
  5. Documentación oficial Inyección de dependencias NestJS

¿Por qué me gusta NestJS para el desarrollo backend con TypeScript?

Si eres como yo y prefieres tener las cosas bien estructuradas y organizadas, es probable que también te gusten los lenguajes más estrictos, como TypeScript en lugar de JavaScript, o los frameworks que imponen una forma estándar de trabajar, como Angular en vez de React. Esto no significa que una opción sea mejor que otra, simplemente son diferentes enfoques, y personalmente me inclino más por este tipo de herramientas (aunque no descarto las demás).

Recientemente he descubierto también Encore.ts, creo que no es tan estructurado pero no lo he trabajado

Bajo esta premisa, NestJS me resulta atractivo porque proporciona una estructura clara y organizada para el desarrollo backend. A veces puede dar dolores de cabeza, su enfoque basado en principios sólidos como la inyección de dependencias y la arquitectura modular hace que el código sea más mantenible y escalable.

A continuación, haré un breve resumen de la arquitectura básica que sigue NestJS.

image

Módulos en NestJS

La idea principal en NestJS es dividir el proyecto en módulos. Pero, ¿qué es exactamente un módulo?
Lo podemos entender como una unidad fundamental que encapsula una parte de la lógica de negocio.

Por ejemplo, si el requisito del cliente es desarrollar un blog con entradas y usuarios, en un primer análisis podríamos identificar dos módulos principales:

  • Módulo de Usuarios
  • Módulo de Entradas

Cada módulo, a su vez, se organiza en distintos componentes esenciales:

  • Controlador: Maneja las solicitudes HTTP y define los endpoints del módulo.
  • Servicio: Contiene la lógica de negocio y actúa como intermediario entre el controlador y los datos.
  • Datos: Generalmente representados por entidades, repositorios o modelos que interactúan con la base de datos.

Para definir un módulo se hace de la siguiente forma:
NestJS Module definition

Controladores

El controlador de un módulo es una clase cuya única función es exponer los endpoints del módulo e interactuar con el cliente. Se encarga de recibir las requests y devolver las responses, pero no implementa ninguna lógica de negocio.

Definición de un controlador en NestJS

El controller debe implementar el servicio, pero en el anterior ejemplo no lo usamos para que sea más sencillo de comprender.

Servicios

Los servicios son clases encargadas de ejecutar la lógica de negocio. Reciben los datos desde el controlador, los procesan y realizan las operaciones necesarias antes de devolver una respuesta.

Son el núcleo de la aplicación y permiten mantener una arquitectura limpia y bien organizada.

Definicion de un servicio en NestJS

El servicio implementará la clase encargada de acceder a los datos, en este caso no lo hacemos para que sea más sencillo de entender. Pero el servicio nunca accederá directamente a los datos.

Datos (Repositorios)

Los datos o repositorios son clases dedicadas exclusivamente** al acceso y gestión de datos**. Pueden obtener información desde bases de datos, ficheros, otras APIs, o cualquier otra fuente externa.

Su función es desacoplar la lógica de acceso a datos del resto de la aplicación, facilitando la mantenibilidad y escalabilidad del proyecto.

En este caso no proporcionaré un ejemplo, ya que la implementación de la clase varía dependiendo de la biblioteca utilizada (mongoose, typeorm, prisma) y la base de datos empleada.

Resumen

En un módulo de NestJS, contamos con tres clases bien diferenciadas, cada una con una responsabilidad específica:

Cada clase cumple su función sin invadir la responsabilidad de las demás, manteniendo una separación clara de responsabilidades.

Además, siguen una jerarquía en la que cada capa solo interactúa con la inferior:

  • El controlador utiliza el servicio, pero el servicio no tiene conocimiento del controlador.

  • El servicio utiliza los repositorios o fuentes de datos, pero estos no conocen al servicio.

Arquitectura módulos Nestjs

Te habrás dado cuenta de que esta estructura sigue los principios de Domain-Driven Design (DDD) y Clean Architecture. Esto es una gran ventaja, ya que nos permite mantener una clara separación de responsabilidades, lo que facilita la organización del código y mejora la testabilidad de cada componente de forma independiente.

Inyección de Dependencias

Otra de las características fundamentales de NestJS es su sistema de inyección de dependencias, un concepto utilizado en frameworks como Spring Boot. Este mecanismo es clave para lograr una mayor flexibilidad y modularidad en nuestras aplicaciones.

Al aplicar este patrón, evitamos la necesidad de instanciar manualmente las clases. Es decir, nunca crearemos objetos con new UserService(). En su lugar, simplemente indicamos que necesitamos una clase del tipo UserService, y NestJS se encargará de gestionar su instancia.

De forma predeterminada las clases que inyectemos son tipo Singleton (DEFAULT), hay que tenerlo en cuenta en ciertas ocasiones.

Cuando una clase es requerida, Nest verifica en su registro interno si ya existe una instancia disponible. Si es así, la reutiliza; de lo contrario, la crea automáticamente. Por defecto, todas las clases inyectadas son Singleton, lo que significa que se instancian una única vez y se comparten en toda la aplicación, optimizando el uso de recursos.

Este enfoque no solo hace que el código sea más limpio y mantenible, sino que también facilita la escalabilidad del proyecto.

Injectable

Cualquier clase anotada con @Injectable es gestionada por el contenedor de dependencias (IoC) de NestJS. Si, por ejemplo, tenemos una clase de utilidades que queremos usar en el módulo de User, debemos importar dicha clase en el módulo y declararla dentro del array de providers. Una vez hecho esto, ya podremos aprovechar la inyección de dependencias.

Existen dos formas principales de inyectar dependencias:

  • En el constructor: la forma recomendada y por defecto.
  • En las propiedades: utilizada en casos específicos, como cuando trabajamos con herencia y necesitamos llamar al método super() de la clase padre.

Inyección en el constructor

Esta es la forma más común y sencilla de hacerlo. Cuando encuentres una clase con un constructor que tenga uno o más argumentos, estos generalmente serán otras clases (o valores) que NestJS inyecta automáticamente en esa clase.

En el ejemplo anterior, tenemos el controlador UserController y el servicio UserService. Según la arquitectura propuesta, el controlador debería utilizar el servicio. Para lograr esto, inyectamos el servicio en el constructor del controlador, y NestJS se encargará automáticamente del resto.

NestJS Inyeccion en el constructor

Inyección en propiedades

Aunque menos común, esta técnica también es válida. La usamos en situaciones específicas, como cuando una clase hereda de otra y necesitamos llamar al método super() del padre. Esto evita que tengamos que modificar ambas clases. Para hacerlo, usamos el decorador @Inject() y le pasamos el token o la clase que queremos inyectar en la propiedad.

Esta opción también es válida para la inyección:

Inyeccion en propiedades NestJS

Documentación oficial Módulos NestJS

Documentation | NestJS - A progressive Node.js framework

Nest is a framework for building efficient, scalable Node.js server-side applications. It uses progressive JavaScript, is built with TypeScript and combines elements of OOP (Object Oriented Programming), FP (Functional Programming), and FRP (Functional Reactive Programming).

favicon docs.nestjs.com

Documentación oficial Inyección de dependencias NestJS

Documentation | NestJS - A progressive Node.js framework

Nest is a framework for building efficient, scalable Node.js server-side applications. It uses progressive JavaScript, is built with TypeScript and combines elements of OOP (Object Oriented Programming), FP (Functional Programming), and FRP (Functional Reactive Programming).

favicon docs.nestjs.com

Top comments (0)

typescript

11 Tips That Make You a Better Typescript Programmer

1 Think in {Set}

Type is an everyday concept to programmers, but it’s surprisingly difficult to define it succinctly. I find it helpful to use Set as a conceptual model instead.

#2 Understand declared type and narrowed type

One extremely powerful typescript feature is automatic type narrowing based on control flow. This means a variable has two types associated with it at any specific point of code location: a declaration type and a narrowed type.

#3 Use discriminated union instead of optional fields

...

Read the whole post now!

👋 Kindness is contagious

If you enjoyed this post, a ❤️ or a quick comment would mean a lot!

Join DEV