The error that says that the dependency can't be resolved is not clear enough. Currently, the error output says:
[ExceptionHandler] Nest can't resolve dependencies of the LeadService (LeadRepository, ?). Please make sure that the argument dependency at index [1] is available in the LeadModule context.
From this output, I can conclude that the dependency ConsentService
of my LeadService
. See LeadService
constructor below.
Additionally, the output also puts the following suggestion:
Potential solutions:
- If dependency is a provider, is it part of the current LeadModule?
My answer: It is a provider, but it's not part of the current module. It's a provider from the ConsentModule. See ConsentModule definition.
- If dependency is exported from a separate @Module, is that module imported within LeadModule?
@Module({
imports: [ /* the Module containing dependency */ ]
})
My answer: Yes, it is exported from the ConsentModule and it is imported in the LeadModule thus I don't understand why is this failing.
ConsentService
@Injectable()
export class ConsentService {
constructor(@InjectRepository(Consent) private repository: Repository<Consent>) {}
}
LeadService
@Injectable()
export class LeadService<T extends LeadPayload> {
constructor(
@InjectRepository(Lead)
private leadRepository: Repository<Lead>,
@Inject()
private consentService: ConsentService
) {}
}
ConsentModule
import { Module } from '@nestjs/common';
import { ConsentService } from './consent.service';
import { Consent } from '../db/models';
import { TypeOrmModule } from '@nestjs/typeorm';
@Module({
imports: [TypeOrmModule.forFeature([Consent])],
providers: [ConsentService],
exports: [ConsentService]
})
export class ConsentModule {}
LeadModule
import { Module } from '@nestjs/common';
import { LeadService } from './lead.service';
import { Lead } from '../db/models';
import { TypeOrmModule } from '@nestjs/typeorm';
import { ConsentModule } from './consent.module';
@Module({
imports: [ConsentModule, TypeOrmModule.forFeature([Lead])],
providers: [LeadService],
exports: [LeadService]
})
export class LeadModule {}
AppModule
@Global()
@Module({
imports: [
ConsentModule,
LeadModule,
TypeOrmModule.forRoot({
...getDbConnectionProperties(),
entities: [Consent, Lead]
})
],
controllers: [
DevController,
HealthController
],
providers: []
})
export class AppModule {}
I would like to know why exactly is the error happening because I think I have declared everything correctly
When you use @Inject
you need to provide the token
(the id) that the container uses to find the object instance. This is handy when, for example you have multiple instances of a class. You can give each instance (a Custom Provider) a name/id (a string token in Nest terminology) and then @Inject("name")
so that Nest will inject the correct instance of the object.
So for your LeadService
Nest doesn't seem to know what instance to inject into the consentService
parameter because you've not specified a token. Because Nest can do matching using the class type as the token, you could write @Inject(ConsentService)
. Nest will realise it needs to instantiate an instance of ConsentService
(with all its dependencies resolved) and then provide that object to the LeadService
constructor.
However often when you're using the class type as the token, it's because you've only got one instance of the class. So you can leave off the @Inject(ConsentService)
entirely. Nest can match based off the types and inject an instance (a singleton instance). So for your application, just remove the @Inject()
decorator from the consentService
constructor parameter.
Now, I'm going to suggest you should not use @Inject()
at all. Why? Because IMO it violates the idea of Inversion of Control. The point of IoC is that the injectee (LeadService
) shouldn't know what it gets injected with. All that matters is that the injected objects meet the type contract. So if you have two instances of ConsentService
for example, which one should LeadService
use? Well LeadService
shouldn't know, but @Inject()
couples LeadService
to an implementation of ConsentService
which limits the reusability/composability of the two classes. If one is following good SOLID principles you may want to compose objects in different combinations. IMO the correct way is to use Custom Provider metadata to specify how to wire objects together using string tokens.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With