Dentro de un módulo, puedes tener la necesidad de utilizar un servicio que pertenece a otro módulo. Importar estos servicios en otros módulos requiere de un paso adicional.
Importaciones de servicios compartidos
Si tienes un Módulo A que posee un Servicio A y un segundo Módulo B requiere hacer uso de este, debes exportar el servicio para que otro módulo pueda utilizarlo.
Debes indicar en la propiedad exports del decorador @Module() que un módulo es exportable para que otro módulo pueda importarlo en sus providers.
De esta manera, evitas errores de compilación de tu aplicación que ocurren cuando importas servicios de otros módulos que no están siendo exportados correctamente.
Ejemplo de interacción entre módulos
A continuación, podrás ver el código que necesitas para hacer que los módulos interactúen entre sí.
// src/users/entities/order.entity.tsimport{User}from'./user.entity';import{Product}from'./../../products/entities/product.entity';exportclassOrder{// // 👈 new entity date:Date; user:User; products:Product[];}
// src/users/controllers/users.controller.ts @Get(':id/orders')// 👈 new endpointgetOrders(@Param('id',ParseIntPipe) id: number){returnthis.usersService.getOrderByUser(id);}
// src/users/services/users.service.ts...import{Order}from'../entities/order.entity';import{ProductsService}from'./../../products/services/products.service';@Injectable()exportclassUsersService{constructor(private productsService:ProductsService){}...getOrderByUser(id:number):Order{// 👈 new methodconst user =this.findOne(id);return{ date:newDate(), user, products:this.productsService.findAll(),};}}
Si alguna vez mientras desarrollan en NestJS y se encuentran con que a pesar de estar exportados e importados los módulos/servicios, y Nest les sigue pidiendo que los añadan, seguramente es porque ambos servicios están siendo llamados el uno al otro, en otras palabras, un círculo vicioso. Para esto Nest implementó la siguiente solución:
import{ forwardRef }from'@nestjs/common';import{ModuloUno}from'modules/moduloUno.module';@Module({imports:[forwardRef(()=>ModuloUno),// fordwardRef nos ayuda a que ambos servicios sean llamados recíprocamente]})
Recuerden utilizar esto para ambos módulos, y también para ambos servicios.
Así quedaría cundo lo inyecten al servicio, gracias Carlos por el aporte.
El fin de la clase es enseñar como se exportan e importan los modulos, pero para fines de logica de negocio, el ejercicio real se haria con la entidad de customer, quienes son lo que clientes que hacen las compras. Ya que users en este caso serian mas como de tipo admin de la tienda.
Hola entiendo su punto de vista pero los users son todas las personas que haran uso de la app, que unos tengan permisos administrativos y otros no eso es otra cosa, pero un usuario administrador puede ser un customer y por tanto tener tambien ordenes de compras.
Lo más común es que se haga con los Guards de tu servidor de Nestjs, debido a que estos deben de ser usados en cada controller de cada module de tu servidor.
Interacción entre Módulos
Los módulos funcionan como islas que se encuentran aisladas, cada uno con sus controladores, services etc., en muchos casos vamos a necesitar que nuestros módulos se comuniquen entre si dependiendo de la lógica del negocio
¿Cómo comunicar módulos?
En el siguiente ejemplo vamos a comunicar el modulo de users con el modulo de products
Entities
Para hacer uso de alguna entiti de otro modulo simplemente importamos la clase:
El el siguiente ejemplo exportamos la entidad Product que hace parte del modulo products en nuestra entidad order que hace parte del modulo de user
Para hacer uso de algún servicio que no haga parte de los servicios de nuestro modulo, lo primero que debemos hacer es importar la clase en nuestro servicio:
En el siguiente ejemplo importamos la clase de ProductService en nuestra clase UserService
Y luego en la clase en la cual necesitamos reutilizar un servicio de otro modulo lo llamamos:
getOrderByUser(id: number):Order{const user =this.findOne(id);return{date:newDate(), user,products:this.productsService.findAll(),};}
Si ejecutamos o probamos nuestro servicio, nos aparecerá un error en consola
El error que nos aparece en la terminal, básicamente nos esta diciendo que ProductServices hace parte de un modulo de ProductServices y no de UserServices lo que genera un problema de colisión.
Solución
Para solucionar este problema, debemos primero indicar en nuestro modulo de products que vamos a exportar nuestro productServices y asi cualquier modulo que lo necesite lo pueda utilizar sin ningún problema:
Es muy bonito Nest, te hace crecer como dev obligandote a seguir arquitecturas y buenas practicas ❤️
¿Podríamos tener un controller y un service para orders?
Con el fin de mantener el principio de única responsabilidad 🤔
No estoy seguro de si el principio de unica responsabilidad aplique tambien a los modulos, pero tambien me planteo la misma pregunta sobre tener aparte las ordenes.
Hola!, estoy desarrollando una API con Nest, sin embargo además de los servicios también hago uso de Repositorios y son estos los que importo en otros módulos en donde los necesito, por ejemplo:
Al hacer esto nunca me ha surgido el problema del Circular Dependency, mi consulta es si esto me traerá algún tipo de desventaja o es una forma válida de trabajar la API.
Gracias de antemano, excelente serie de cursos :D
Es una forma muy válida de trabajar con TypeORM y además una muy buena práctica te felicito 🎉 estás yendo más allá y aprovechando al máximo TypeORM.
Como es que se llama esta arquitectura?
La arquitectura que nos brinda esta basada en Controladores, Servicios y Modelos de datos.
Creo usa arquitectura modular, pero he visto que pueden usar arquitectura hexagonal y MVC.
¿se podria crear un modulo data-source y ahi crear todos los sericos y que los demas modulos lo usen?
Sí, se puede crear un módulo 'data-source' y definir allí los servicios para que los demás módulos los utilicen. Esto permite una mejor organización y reutilización del código.
Tengo una duda, con este servicio:
getOrderByUser(id: number):Order{const user =this.findOne(id);return{date:newDate(),user,products:this.productsService.findAll(),};}
Se supone que debe traer las ordenes por usuario pero en ningún lado filtras por usuario, solo veo que se obtiene el usuario y luego se obtiene todos los productos, no entendi bien esa parte, si me explicas… gracias!!
Hola, si claro te explico recuerda que nos estamos enfocando en programación modular así que lo único que hicimos es que retorne el esquema solicitado aún no hemos filtrado por usuario eso lo haremos en los cursos de persistencia con Postgres o Mongo.
Con respecto a esta estructura para los proyectos, es la más recomendable? Sigue estando vigente? Digo porque desde mi punto de vista me parece un poco desordenada. Saludos
Tengo todo en módulos (islas) pero al hacer el Get, aparece error 404. ¿qué me puede faltar hacer?
No es una entity lo que creo, es solo una clase? para mostrar la información de dos tablas
Si fuese una entidad tendría que hacer con relaciones de una a muchos, por ejemplo ?
No me quedo muy claro cuando utilizar esta creación de "entity" o clase, pero muy buena forma de resolver
Hola, siempre se tiene que usar @Entity en el caso de la clase aún no creamos la tabla de órdenes de compra así no hemos llegado a ese punto, pero siempre que tengas una clase y este representa una tabla en tu DB debes usar @Entity.
Y recuerda que @Entity es solo útil con TypeORM ya en los siguientes cursos vamos a trabajar con bases de datos relacionales y no relacionales.
¿Por qué se instancia productsService en el constructor? y como privado?
at Object.<anonymous> (C:\Users\nicol\Documents\Cursos\nestjs-modular\src\users\services\users.service.ts:11:40)
at Module._compile (node:internal/modules/cjs/loader:1256:14)
at Object.Module._extensions..js (node:internal/modules/cjs/loader:1310:10)
at Module.load (node:internal/modules/cjs/loader:1119:32)
at Function.Module._load (node:internal/modules/cjs/loader:960:12)
at Module.require (node:internal/modules/cjs/loader:1143:19)
at require (node:internal/modules/cjs/helpers:121:18)
at Object.<anonymous> (C:\Users\nicol\Documents\Cursos\nestjs-modular\src\users\controllers\users.controller.ts:12:1)
at Module._compile (node:internal/modules/cjs/loader:1256:14)
at Object.Module._extensions..js (node:internal/modules/cjs/loader:1310:10)
Esttoyy tenniendo este error al coorrerr el servidor
importaria en modulo de ProductModule en el modulo de UserModule y listo.
Para lograr usar el Servicio A que hace parte de Módulo A en el Módulo B debemos exportar el Servicio A y luego importar el Módulo A en el Módulo B. 😮
Para los que han trabajado con Angular, se les va a facilitar entender como usar este framework.
Es primera vez en todos los cursos del Platzi que la consola me da el mismo error que el profesor _
Pues cuales has visto? .-.
Si ya tienes práctica con los módulos de angular, se te hará muy familiar esta manera de trabajar, creo que es muy parecido, sino que igual, incluso los nombres de los arrays de los módulos, excepto por el de controllers, y en angular esta el de declarations.
Ahora que lo pienso no seria mala idea aprender Angular, debido a que aprendí Nestjs primero, pero creo que no debería de ser muy dificil brincar de uno a otro.