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.
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.
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
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.
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.
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
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.
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.
Cual es la diferencia de exportar el servicio como providers, ya eso también soluciona el error
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: