Circular dependency between modules in nestjs - node.js

The official doc is not clear about how modules in nestjs work and I'm having a problem with a circular dependency. It seems like my module structure is messed up I would like to understand what is wrong with it. The error I'm getting reads:
Nest cannot create the module instance. Often, this is because of a
circular dependency between modules. Use forwardRef() to avoid it.
(Read more: https://docs.nestjs.com/fundamentals/circular-dependency)
Scope [AppModule -> UsersModule -> CategoriesModule]
Here are the import parts of all the modules mentioned in the error message.
AppModule:
UsersModule,
SmsRegistrationModule,
AuthModule,
SubscriptionModule,
EmailModule,
EntriesModule,
CategoriesModule,
AwsModule,
SharedModule
UsersModule:
CategoriesModule
CategoriesModule:
AwsModule,
SharedModule,
The error raised when I added SharedModule to the CategoriesModule module. Seems like I'm missing something on how these modules communicate and thus can't resolve this error.
Your help would be much apprecicted.
EDIT:
SharedModule:
#Module({
providers: [
CacheService,
CodeGenService,
IsUniqueEmail,
BasicFileService,
],
imports: [
CacheModule.registerAsync({
imports: [ConfigModule],
useClass: CacheConfigService,
}),
UsersModule,
AwsModule,
],
exports: [
CacheService,
CodeGenService,
IsUniqueEmail,
BasicFileService,
],
})
export class SharedModule {}

Your SharedModule imports UserModule, so the import chain (or at least the one I'm going to follow here) is AppModule -> UsersModule -> CategoriesModule -> SharedModule -> UsersModule -> CategoriesMOdule -> SharedModule -> .... To get around this, either the SharedModule should not import the UsersModule, or you should forward reference the CategoriesModule from the UserModule, the UserModule from the SharedModule and the SharedModule from the CategoriesModule. This is my first time seeing a circular dependency a few modules deep, so I can't give the exact syntax of how to work with the forwardRef method.

Related

Nest can't resolve dependency, but it's definitely there

I have a weird behaviour. Nest is complaining about a missing dependency in a service, but only if that service is Injected by multiple other services
cleaning.module.ts
#Module({
imports: [
//Just a few repos
],
providers: [
ServicesService,
...
AreasService,
RoomsService,
...
],
controllers: [
...
],
exports: [
ServicesService,
...
AreasService,
RoomsService,
...
]})
services.module.ts, areas.module.ts and rooms.module.ts are basically the same
#Module({
imports: [CleaningModule],
providers: [],
controllers: [],
exports: []
})
rooms.service.ts
constructor(#InjectRepository(Room) private readonly repo: Repository<Room>, private areasService: AreasService) { }
services.service.ts
constructor(#InjectRepository(Service) private readonly repo: Repository<Service>, ... private roomsService: RoomsService) { }
With this, I get the following error:
ERROR [ExceptionHandler] Nest can't resolve dependencies of the RoomsService (RoomRepository, ?). Please make sure that the argument dependency at index [1] is available in the CleaningModule context.
So, it's missing AreasService somehow. Which is clearly provided by the CleaningModule.
But the weird thing is, if I remove the injection of the RoomsService in the ServicesService constructor, then everything works just fine. And I don't have the slightest idea why this is the case...
Based on the error it seems like you have a circular file import going on from your roo.service.ts to your area.service.ts. This could be several files deep like room.service.ts imports area.service.ts that another that imports another that imports another that finally imports room.service.ts again or it could be the use of barrel files. If this truly is a circular dependency (room uses area which uses room) then you need to use #Inject(forwardRef(() => OtherService)). Otherwise, you need to figure out a way to avoid the circular import

NestJs can't resolve service dependencies on a circular dependency

i have the problem that i have a circular dependency in my project. Unfortunately I cannot solve this with forwardRef.
The following structure:
OrderModule
OrderService
I have the following dependencies in the orderService
PriceService
CustomerService
SalePriceService
...
PriceModule
PriceService
I have the following dependencies in the priceService
OrderService
ProductService
...
I've tried all the options from the Official Documentation.
docs NestJs circular-dependency
What has to be considered here if there are more dependencies in a service?
Many thanks. Best regards.
Update:
order.module.ts
#Module({
imports: [
CustomerModule,
ProductModule,
MongooseModule.forFeature([{ name: 'Order', schema: OrderSchema }]),
forwardRef(() => PriceModule),
],
controllers: [OrderController],
providers: [OrderService],
exports: [OrderService],
})
export class OrderModule {}
order.service.ts
#Injectable()
export class OrderService extends GenericCrudService<OrderDocument> {
constructor(
#InjectModel(Order.name) readonly order: Model<OrderDocument>,
private readonly productService: ProductService,
#Inject(forwardRef(() => PriceService))
private readonly priceService: PriceService,
) {
super(order);
}
}
price.module.ts
#Module({
imports: [
CustomerModule,
SalePriceModule,
MongooseModule.forFeature([{ name: 'Price', schema: PriceSchema }]),
forwardRef(() => OrderModule),
],
controllers: [],
providers: [PriceService],
exports: [PriceService],
})
export class PriceModule {}
price.service.ts
#Injectable()
export class PriceService extends GenericCrudService<PriceDocument> {
constructor(
#InjectModel(Price.name) readonly price: Model<PriceDocument>,
private readonly customerService: CustomerService,
private readonly salePriceService: SalePriceService,
#Inject(forwardRef(() => OrderService))
private readonly orderService: OrderService,
) {
super(price);
}
}
product.module.ts
#Module({
imports: [
PriceModule,
MongooseModule.forFeature([{ name: 'Product', schema: ProductSchema }]),
],
controllers: [ProductController],
providers: [ProductService],
exports: [ProductService],
})
export class ProductModule {}
product.service.ts
#Injectable()
export class ProductService extends GenericCrudService<ProductDocument> {
constructor(
#InjectModel(Product.name) readonly product: Model<ProductDocument>,
) {
super(product);
}
}
The error I'm getting is:
The module at index [1] of the OrderModule "imports" array is undefined.
Potential causes:
- A circular dependency between modules. Use forwardRef() to avoid it. Read more: https://docs.nestjs.com/fundamentals/circular-dependency
- The module at index [1] is of type "undefined". Check your import statements and the type of the module.
Scope [AppModule -> ProductModule -> PriceModule]
Error: Nest cannot create the OrderModule instance.
The module at index [1] of the OrderModule "imports" array is undefined.
Potential causes:
- A circular dependency between modules. Use forwardRef() to avoid it. Read more: https://docs.nestjs.com/fundamentals/circular-dependency
- The module at index [1] is of type "undefined". Check your import statements and the type of the module.
Scope [AppModule -> ProductModule -> PriceModule]
So there's the obvious circular dependency that you have here: OrdersModule to PricesModule and back, that one is properly forwardReffed. However, there's another, not so obvious circular dependency too. OrdersModule to ProductsModule to PricesModule because the next import would be OrdersModule. Because of this, OrdersModule needs to forwardRef the ProductsModule and ProductsModule needs to forwardRef the PricesModule. It looks like the services themselves aren't circular, so it's just the modules that need the forward ref. Always make sure to check the entire import chain, especially when Nest is trying to report something like it did with Scope [AppModule -> ProductModule -> PriceModule].

How to register RedisModule in Nest.js?

I've followed the instruction from nestjs-redis documentation to register RedisModule but it gives me the following error message. I am new to Nest.js and have no idea how to fix this error.
If you know the better way to use Redis with nestjs, please suggest me.
Nest can't resolve dependencies of the RedisCoreModule
(Symbol(REDIS_MODULE_OPTIONS), ?). Please make sure that the argument
ModuleRef at index [1] is available in the RedisCoreModule context.
Potential solutions:
If ModuleRef is a provider, is it part of the current RedisCoreModule?
If ModuleRef is exported from a separate #Module, is that module imported within RedisCoreModule? #Module({
imports: [ /* the Module containing ModuleRef */ ] })
my app.module
#Module({
imports: [
RedisModule.register({
host: `${host}`,
port: 6379,
}),
],
})
export class AppModule {}

How to create service with Repository exports?

I created service with several repository:
#Injectable()
export class DataService {
constructor(
#InjectRepository(ClassicPrices, 'connect')
private classicPrices: Repository<ClassicPrices>,
#InjectRepository(ModernPrices, 'connect')
private modernPrices: Repository<ModernPrices>,
) {}
public pricesRepository(server): Repository<ModernPrices | ClassicPrices> {
switch (server) {
case 'modern':
return this.modernPrices;
case 'classic':
return this.classicPrices;
}
}
}
Data module settings:
#Module({
imports: [
TypeOrmModule.forFeature([
ClassicPrices,
ModernPrices
], 'connect'),
],
providers: [DataService],
exports: [DataService]
})
export class DataModule {}
When I use it in another modules^ I have error "Nest can't resolve dependencies of the DataService (connect_ClassicPrices). Please make sure that the argument connect_ClassicPrices at index [2] is available in the DataModule context.
Potential solutions:
If connect_ClassicPrices is a provider, is it part of the current DataModule?
If connect_ClassicPrices is exported from a separate #Module, is that module imported within DataModule?
#Module({
imports: [ /* the Module containing connect_ClassicPrices */ ]
})
How to export repository ?
If you want to use a repository from DataModule in other modules you need to add TypeOrmModule to the exports array in DataModule:
exports: [DataService, TypeOrmModule]
Then, any module that imports DataModule can use the repositories registered with TypeOrmModule.forFeature. Generally it's a better practice to export just the services and keep the repositories scoped to their module because that makes your app more modular.

I'm getting following "Nest can't resolve dependencies of the WorkspaceController..." error in nest.js

I get this error
Nest can't resolve dependencies of the WorkspaceController (?). Please make sure that the argument API_SERVICE at index [0] is available in the WorkspaceModule context.
I have this code
app.module.ts
#Module({
imports: [
ClientsModule.register([
{
name: 'API_SERVICE',
transport: Transport.REDIS,
options: {
url: 'redis://localhost:6379'
}
}
]),
WorkspaceModule
],
controllers: [AppController],
providers: [AppService]
})
workspace.module.ts
#Module({
imports: [],
controllers: [WorkspaceController]
})
export class WorkspaceModule {}
workspace.controller.ts
#Controller()
export class WorkspaceController{
constructor(#Inject('API_SERVICE') private client: ClientProxy) {}
#Get("default-languages")
getDefaultLanguages():Observable<string[]> {
return this.client.send<any>({cmd:'getDefaultLanguages'},{});
}
}
You register the ClientsModule inside of AppModule which means that controlelrs and providers in AppModule's scope (i.e. in its own providers and controllers arrays) have access to that provider (#Inject('API_SERVICE')), but once you leave to another module's scope (like WorkspaceModule), that provider is no longer available. If you need that microservice client in several different modules, I'd suggest making a wrapper module for it, that imports and exports the ClientsModule, otherwise, you just need to move the ClientsMOdule.register from AppModule to WorkspaceModule
Example Wrapper
#Module({
imports: [ClientsModule.register(clientsModuleOptions)],
exports: [ClientsModule],
})
export class WrapperClientsModule {}
It's called module re-exporting

Resources