I have two modules whose services are dependent on one another.
// organization.module.ts
//...imports
#Module({
imports: [
forwardRef(() => EmployeeModule),
TypeOrmModule.forFeature([
OrganizationRepository,
Employee
])
],
controllers: [OrganizationController],
providers: [
OrganizationService
]
})
export class OrganizationModule {}
Organization Service*
#Injectable()
export class OrganizationService {
constructor(
#InjectRepository(OrganizationRepository)
private orgRepository: OrganizationRepository,
#InjectRepository(Employee)
private employeeRepsoitory: Repository<Employee>,
private readonly employeeService: EmployeeService,
){}
//...
}
Then i have my employee module and service
employee.module.ts
#Module({
imports: [
forwardRef(() => OrganizationModule),
//...
]
controllers: [EmployeeController],
providers: [EmployeeService, JwtStrategy],
exports: [EmployeeService],
})
export class EmployeeModule {}
and then i have my employee service
employee.service.ts
#Injectable()
export class EmployeeService {
constructor(
private readonly organizationService: OrganizationService
) {}
Now i am getting this DI error and i dont know what is going wrong here. I have tried
#Inject(forwardRef(() => Service)) but didnt seem to work.
My app.module.ts looks like
//...
#Module({
imports: [
OrganizationModule,
],
controllers: [AppController],
providers: [
AppService,
],
})
export class AppModule {}
What am i doing wrong?
You are missing an exports in OrganizationModule.
Add to OrganizationModule:
exports: [OrganizationService]
Related
I am writing end-to-end tests in NestJs and using the "overrideProvider" function to setup test versions of various services (e.g. services that require database connections). I noticed though that even when I do this, the original implementation that injects the real database is still instantiated.
Is there a way to tell Nest to not create transitive dependencies that are overridden?
For example, I have a test that starts like:
...
beforeAll(async () => {
const moduleRef = await Test.createTestingModule({
imports: [ServiceModule],
})
// Works if I uncomment these lines:
// .overrideProvider('Database')
// .useValue(new TestDatabase())
.overrideProvider('ServiceUsingDatabase')
.useValue(new TestService())
.compile();
...
Where the module setup is like:
import { Inject, Injectable, Module } from '#nestjs/common';
interface Database {}
#Injectable()
class ProductionDatabase implements Database {
constructor() {
throw('Cannot create a production database.');
}
}
#Injectable()
export class TestDatabase implements Database {
constructor() {
console.log('Creating the test database.');
}
}
#Module({
providers: [
{
provide: 'Database',
useClass: ProductionDatabase
}
],
exports: ['Database']
})
class DatabaseModule {}
interface Service {}
#Injectable()
class ProductionService implements Service {
constructor(#Inject('Database') private readonly database: Database) {}
}
#Injectable()
export class TestService implements Service {
// Test implementation of the service does not Inject anything.
}
#Module({
imports: [DatabaseModule],
providers: [
{
provide: 'ServiceUsingDatabase',
useClass: ProductionService
}
],
})
export class ServiceModule {}
But, the DI system is still seeming to try and instantiate ProductionDatabase. If I explicitly override the provider for the 'Database' it works, but I'd like to avoid having to explicitly list all transitive dependencies as such.
I ended up deciding to make a "Test" Module for every Module e.g.:
import { Inject, Injectable, Module } from '#nestjs/common';
interface Database {}
#Injectable()
class ProductionDatabase implements Database {
}
#Injectable()
export class TestDatabase implements Database {
}
#Module({
providers: [
{
provide: 'Database',
useClass: ProductionDatabase
}
],
exports: ['Database']
})
class DatabaseModule {}
#Module({
providers: [
{
provide: 'Database',
useClass: TestDatabase
}
],
exports: ['Database']
})
class TestDatabaseModule {}
interface Service {}
#Injectable()
class ProductionService implements Service {
constructor(#Inject('Database') private readonly database: Database) {}
}
#Injectable()
export class TestService implements Service {
}
#Module({
imports: [DatabaseModule],
providers: [
{
provide: 'ServiceUsingDatabase',
useClass: ProductionService
}
],
})
export class ServiceModule {}
#Module({
providers: [
{
provide: 'ServiceUsingDatabase',
useClass: TestService
}
],
})
export class TestServiceModule {}
etc... Though it turned out after some refactorings that the "Test" module wasn't needed as some Modules became pure business logic.
So, I have my RootModule, a ProductModule and a StoreModule.
My RootModule:
#Module({
imports: [
ProductModule,
StoreModule,
],
controllers: [],
providers: [],
})
export class RootModule {}
My ProductModule:
#Module({
providers: [ProductService],
exports: [],
})
export class ProductModule {}
My StoreModule:
#Module({
imports: []
providers: [StoreService, StoreWaitingService],
})
export class ProductModule {}
Since my RootModule imports ProductModule, shouldn't I be able to use ProductService on StoreService and StoreWaitingService?
What if I imported ProductModule on StoreModule imports?
You can use Product Module and Service in StoreService
Product Module
#Module({
providers: [ProductService],
exports: [ProductService],
})
export class ProductModule {}
Store Module
#Module({
imports: [ProductModule],
})
export class StoreModule{}
Store service
import ProductService from '<Product Service Path>';
...
constructor(private readonly productService: ProductService){}
...
//in Function
this.productService.someFunction();
But if you don't want to import the product module in Store Module, you can make the Product Module a global Module -
https://docs.nestjs.com/modules#global-modules
Okay so I'm using TYPEORM_ prefixed environment variables to register TypeOrmModule into my app. Then I'm loading entities using .forFeature() like so:
#Module({
imports: [TypeOrmModule.forFeature([Foo])],
controllers: [FooController],
providers: [FooService],
exports: [TypeOrmModule],
})
export class FooModule {}
No matter whether I use forRoot() or forRoot({ autoLoadEntities: true }) in AppModule, I get RepositoryNotFoundError: No repository for "Foo" was found. Looks like this entity is not registered in current "default" connection? error while working with the dev server. Any idea what's going on? My service looks like:
#Injectable()
export class FooService {
constructor(#InjectRepository(Foo) private readonly fooRepository: Repository<Foo>) {}
}
I tried the followings as single and/or combined, still didn't solve the issue.
Put a name in #Entity() decorator.
#Entity('foo')
export class Foo {}
Try forRootAsync().
#Module({
imports: [
TypeOrmModule.forRootAsync({
useFactory: async () =>
Object.assign(await getConnectionOptions(), { autoLoadEntities: true }),
}),
FooModule,
],
controllers: [AppController],
providers: [AppService],
})
export class AppModule {}
Pass 'default' to forFeature().
#Module({
imports: [TypeOrmModule.forFeature([Foo], 'default')],
controllers: [FooController],
providers: [FooService],
exports: [TypeOrmModule],
})
export class FooModule {}
Try using entities key in forRoot().
#Module({
imports: [
TypeOrmModule.forRoot({ entities: [Foo] }),
FooModule,
],
controllers: [AppController],
providers: [AppService],
})
export class AppModule {}
try to define connectionName inside getConnectionOptions
example:
#Module({
imports: [
TypeOrmModule.forRootAsync({
useFactory: async () =>
Object.assign(await getConnectionOptions('default'), { autoLoadEntities: true }),
}),
FooModule,
],
controllers: [AppController],
providers: [AppService],
})
export class AppModule {}
enter image description here
I have been having a dependency problem that is solved by injecting the service and using forwardRef, but this generates a strange error and the service responds only once and then the dependencies are lost, example: when calling the service the first time it returns the response, when trying to consume it again I get this error "Cannot read property 'axiosRef' of undefined" as if the HttpService was no longer available.
enter image description here
auth0.module.ts
#Module({
imports: [HttpModule, forwardRef(() => UsersModule)],
controllers: [Auth0Controller],
providers: [Auth0Service, ConfigService],
})
export class Auth0Module {}
auth0.service.ts
export class Auth0Service {
constructor(
#Inject(forwardRef(() => UsersService))
private usersService: UsersService,
private httpService: HttpService,
private configService: ConfigService,
) {}
users.module.ts
#Module({
imports: [
DatabaseModule,
HttpModule,
forwardRef(() => SquareModule),
TenantModule,
],
controllers: [UsersController],
providers: [UsersService, ...usersProviders],
exports: [...usersProviders, UsersService],
})
export class UsersModule {}
users.service.ts
export class UsersService {
constructor(
private squareService: SquareService,
#Inject(REQUEST) private request: Request,
#Inject('USER_MODEL') private usersModel: Model<any>,
) {}
square.module.ts
#Module({
imports: [
HttpModule,
forwardRef(() => UsersModule),
forwardRef(() => TenantModule),
],
controllers: [SquareController],
providers: [
SquareService,
ConfigService,
SDKSquareService,
CryptoService,
Auth0Service,
TokenService,
],
exports: [
SquareService,
ConfigService,
SDKSquareService,
CryptoService,
Auth0Service,
],
})
export class SquareModule {}
square.service.ts
export class SquareService {
constructor(
private configService: ConfigService,
private sdkSquareService: SDKSquareService,
private tenantService: TenantService,
private auth0Service: Auth0Service,
private tokenService: TokenService,
private httpService: HttpService,
#Inject('USER_MODEL') private userModel: Model<any>,
#Inject('TENANT_MODEL') private tenantModel: Model<any>,
) {}
I'am trying to use AuthService into UsersService and UsersService into AuthService, so this is called "circular dependency". The issue is that "Nest can't resolve dependencies of the AuthService (UserModel, JwtService, ?). Please make sure that the argument dependency at index [2] is available in the AuthModule context."
UsersModule:
#Module({
imports: [
MongooseModule.forFeature([
{
name: User.name, schema: UserSchema
}
]),
forwardRef(() => AuthModule),
],
controllers: [UsersController],
providers: [UsersService],
exports: [UsersService]
})
export class UsersModule {}enter code here
AuthModule:
#Module({
imports: [
MongooseModule.forFeature([{name: User.name, schema: UserSchema}]),
JwtModule.register({ secret: process.env.JWT_SECRET }),
forwardRef(() => UsersModule),
],
controllers: [AuthController],
providers: [AuthService, JwtStrategy],
exports: [AuthService, JwtModule]
})
export class AuthModule {}
UsersService (works fine):
#Injectable()
export class UsersService {
constructor(
#InjectModel(User.name) private userModel: Model<UserDocument>,
private jwtService: JwtService,
private authService: AuthService
) {}
...
AuthService (where error occurs):
#Injectable()
export class AuthService {
constructor(
#InjectModel(User.name) private userModel: Model<UserDocument>,
private jwtService: JwtService,
private userService: UsersService,
) {}
...
You've resolved the circular dependency between the modules, but not between the services. Each side of the service needs #Inject(forwardRef(() => InjectedClass)). So your AuthService would use #Inject(forwardRef(() => UserService))
Circular dependencies are bad and trying to get around them using things like forwardRef mentioned in the other answer is not good practice.
Look into other patterns for inter-service communication. Events for example: https://docs.nestjs.com/techniques/events