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.
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 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].
I am trying to create a super simple cron task
#Injectable()
export class CronService {
constructor(
#Inject(forwardRef(() => PurchaseService))
private purchaseService: PurchaseService) {}
#Cron('45 * * * * *')
handleCron() {
this.purchaseService.handleOldPurchases();
}
}
when I define the service in the module in the imports section, it runs only if I drop the purchase service injectionm if I add it to the providers section - it simply doesn't run in production :(
#Module({
imports: [
CronService,
],
runs the cron - but throws Nest can't resolve dependencies of the CronService (?). Please make sure that the argument PurchaseService at index [0] is available in the CronService context.
#Module({
providers: [
CronService,
],
doesn't run at all
Assuming your PurchaseService is in the same module as CronService
PurchaseService:
#Injectable()
export class PurchaseService {
handleOldPurchases() {}
}
CronService:
#Injectable()
export class CronService {
constructor(private _purchaseService: PurchaseService) {}
#Cron('45 * * * * *')
handleCron() {
this._purchaseService.handleOldPurchases();
}
}
CronModule:
#Module({
providers: [CronService, PurchaseService]
})
export class CronModule {}
If your CronService and PurchaseService are in different modules, the module that contains PurchaseService has to provide and export PurchaseService and the module that consumes the PurchaseService has to import the PurchaseModule
PurchaseModule:
#Module({
providers: [PurchaseService], // this tells the interpreter this module offers PurchaseService
exports: [PurchaseService] // this tells the interpreter for those modules that import PurchaseModule can have access to PurchaseService
})
export class PurchaseModule {}
CronModule:
#Module({
imports: [PurchaseModule] // this tells the interpreter this module require some services in PurchaseModule
providers: [CronService],
})
export class CronModule {}
Lastly, only use forwardRef() if and only if services are mutually dependent, i.e. Service A consumes methodB() of Service B, while Service B is also consuming methodA of Service A. IMHO, you should try your best to avoid this kind of coupling.
If you need more help, NestJS discord: https://discord.com/invite/nestjs
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 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