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].
Related
I'm trying to setup a graphql nestjs clean architecture, I have my resolver call the service, service calls repository and repository calls orm methods. Am I missing a step?
But I get this error:
[Nest] 59764 - 03/10/2022, 16:36:13 ERROR [ExceptionHandler] Nest can't resolve dependencies of the AthleteRepository (?). Please make sure that the argument AthleteEntityRepository at index [0] is available in the GraphQLModule context.
Potential solutions:
- If AthleteEntityRepository is a provider, is it part of the current GraphQLModule?
- If AthleteEntityRepository is exported from a separate #Module, is that module imported within GraphQLModule?
#Module({
imports: [ /* the Module containing AthleteEntityRepository */ ]
})
Error: Nest can't resolve dependencies of the AthleteRepository (?). Please make sure that the argument AthleteEntityRepository at index [0] is available in the GraphQLModule context.
This is my module:
#Module({
imports: [
InfraestructureModule,
NestGraphqlModule.forRoot<MercuriusDriverConfig>({
driver: MercuriusDriver,
graphiql: true,
autoSchemaFile: join(
process.cwd(),
'src/infraestructure/graphql/schema.gql',
),
sortSchema: true,
}),
],
controllers: [AuthResolver, UserResolver],
providers: [
FirebaseService,
AthleteEntity,
AthleteRepository,
AthleteService,
],
})
export class GraphQLModule {}
Adding repository by comment request, it's mostly just wrappers around the typerom Repository.
import { Controller } from '#nestjs/common';
import { InjectRepository } from '#nestjs/typeorm';
import { Repository } from 'typeorm';
import { AthleteEntity } from '../entity/athlete.entity';
#Controller('')
export class AthleteRepository {
constructor(
#InjectRepository(AthleteEntity)
private athleteRepository: Repository<AthleteEntity>,
) {}
async getAthleteByUserId(id: string): Promise<AthleteEntity> {
return this.athleteRepository.findOne({ where: { id } });
}
async getAthletes(): Promise<AthleteEntity[]> {
return this.athleteRepository.find();
}
}
As you use #InjectRepository(AtheleteEntity) you need to have TypeOrmModule.forFeature([AtheleteEntity]) used in the imports of the GraphQlModule.
Side note: Is that supposed to be #Controller() or #Injectable()? It doesn't look like a standard HTTP or RPC controller to me
change AthleteRepository to an #Injectable instead of #Controller.
I import a module in other module but a can access the service in other context
The module when i exported
#Module({
controllers: [ModuleController],
providers: [
ModulesAcessService,
ModulesRepository,
ModulesService
],
exports: [ModulesService, ModulesRepository, ModulesAcessService],
imports: [
TypeOrmModule.forFeature([ModuleEntity]),
forwardRef(() => CoursesModule),
forwardRef(() => LessonsModule)
]
})
export class ModulesModule { }
The module when i imported - ModulesModule
#Module({
controllers: [LessonsController],
providers: [
LessonsService,
LessonsAcessService,
LessonsRepository,
UserLessonsService,
UserLessonsRepository,
UserLessonsSubscriber,
UserLessonsEvents
],
exports: [LessonsRepository,LessonsService, LessonsAcessService, UserLessonsService],
imports: [
TypeOrmModule.forFeature([Lesson, UserLesson]),
forwardRef(() => CoursesModule),
forwardRef(() => ModulesModule)
]
})
export class LessonsModule { }
The error message
Nest can't resolve dependencies of the LessonsService (LessonsAcessService, UserLessonsService, UrlHelper, LessonsRepository, CoursesService, ?). Please make sure that the argument dependency at index [5] is available in the LessonsModule context.
The import in my service - I can't access the ModulesService.
import { ModulesService } from '../modules/modules.service';
#Injectable()
export class LessonsService {
constructor(
private lessonsAccessService: LessonsAcessService,
private userLessonsService: UserLessonsService,
private urlHelper: UrlHelper,
private lessonsRepository: LessonsRepository,
private coursesService: CoursesService,
private modulesService: ModulesService
) { }
...
Node version 14.7.0
Nestjs version 7
You need to make use of the forwardRef for the services too, not just the modules. In your ModulesService use #Inject(forwardRef(() => LessonsService)) on the lessonsService. In the LessonsService use #Inject(forwardRef(() => ModulesService)) on the modulesService.
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 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
I can't find out, where my problem is. I get the following error:
Nest can't resolve dependencies of the BService (?, AService). Please
make sure that the argument at index [0] is available in the CModule
context.
I have 3 Modules, A, B, C.
C should be able to use services from B, and B should call services from A.
A and B have TypeOrm imports and an entity each.
Here is the code:
app.modules.ts:
#Module({
imports: [
TypeOrmModule.forRoot(),
CModule
]
})
export class AppModule {}
c.module.ts:
#Module({
imports: [BModule],
controllers: [CController],
providers: [BService]
})
export class CModule {}
b.module.ts:
#Module({
imports: [
AModule,
TypeOrmModule.forFeature([B], 'default')
],
providers: [BService],
exports: [AModule, BService]
})
b.entity.ts:
#Entity()
export class B {
#PrimaryGeneratedColumn()
id: number;
#Column()
name: string;
}
b.service.ts:
#Injectable()
export class BService {
constructor(
#InjectRepository(B, 'default')
private readonly bRepository: Repository<B>,
private readonly aService: AService
) {}
}
a.module.ts:
#Module({
imports: [
TypeOrmModule.forFeature([A], 'default')
],
providers: [AService],
exports: [AService]
})
export class AModule {}
a.entity.ts:
#Entity()
export class A {
#PrimaryGeneratedColumn()
id: number;
#Column()
name: string;
}
a.service.ts:
#Injectable()
export class AService {
constructor(
#InjectRepository(A, 'default')
private readonly aRepository: Repository<A>) {
}
}
In your CModule you do not need to define providers: [BModule] as you will overwrite the value given from BModule. As BModule already exports BService you shouldn't need to do anything other than import BModule into your CModule then you can use BService with no problems.
Side remark: is there any reason you have dependencies across your modules? Most of the time if you can keep from importing other modules if it isn't necessary it'll make a lot of your code easier to work with.