Nest can't resolve dependencies to exported service - javascript

I'm trying to export and import a service in NestJS. It seems easy and I thought it should work like this but I got an error saying that Nest can't resolve the dependencies.
SettingsModule
This module has the service that should be imported, and exports it.
#Module({
imports: [
MongooseModule.forFeature([{ name: Setting.name, schema: SettingSchema }]),
],
providers: [SettingsService],
exports: [SettingsService],
})
export class SettingsModule {}
MsgraphModule
This module should import the service through the module because the service is injected in their service.
#Module({
imports: [SettingsModule],
providers: [MsgraphService],
})
export class MsgraphModule {}
AppModule
#Module({
imports: [
MongooseModule.forRoot('mongodb://localhost/lead-import', {
useCreateIndex: true,
}),
MsgraphModule,
SettingsModule,
...
],
controllers: [AppController],
providers: [AppService],
})
export class AppModule {}
What am I doing wrong here?

The problem was that I used the #Inject() decorator which is only needed for custom dependency injections.
#Injectable()
export class MsgraphService {
private client: Client;
private authenticator;
constructor(#Inject() private settingsService: SettingsService) {
this.init();
this.authenticator = new MSGraphAuthenticator();
}
...
}
So removing the #Inject() did the trick.

Related

Nest can't resolve dependencies .Please make sure that the argument ImageFileS ervice at index [1] is available in the ItemModule context

I get this error
ERROR [ExceptionHandler] Nest can't resolve dependencies of the ItemController (ItemService, ?). Please make sure that the argument ImageFileS
service at index [1] is available in the ItemModule context.
I have this code
ImageFileModule :
#Module({
imports: [TypeOrmModule.forFeature([ImageFile]), ConfigModule, ItemModule],
controllers: [ImageFileController],
providers: [ImageFileService],
exports: [ImageFileService],
})
export class ImageFileModule {}
ItemModule :
#Module({
imports: [TypeOrmModule.forFeature([Item])],
controllers: [ItemController],
providers: [ItemService],
exports: [ItemService],
})
export class ItemModule {}
Service That I am trying to use:
#Injectable()
export class ImageFileService {
constructor(
#InjectRepository(ImageFile)
private readonly imageFileRepository: Repository<ImageFile>,
private readonly configService: ConfigService,
private readonly itemService: ItemService,
) {}

Nest can't resolve dependencies of the NodeMailerService (?, AppConfigService)

I am facing this error although I have imported MailerModule in app.module and using it in other module named 'user.module'.
Attaching error Image and code
App.Module
import { NodeMailerService } from './mailer/mailer.service';
#Module({
imports: [
MailerModule.forRootAsync({
inject: [AppConfigService],
useFactory: (configService: AppConfigService) => {
const config = configService.smtpEmailObject;
return { ...config }
},
})
})
export class AppModule { }
Users.Module
import { NodeMailerService } from '../mailer/mailer.service';
#Module({
imports: [],
providers: [UsersService, ...userProviders, ...userMetaProviders,NodeMailerService],
exports: [UsersService],
controllers: [UsersController]
})
export class UsersModule { }
Error Image
Create MailerModule, add NodeMailerService to the providers and export NodeMailerService from it. Then import MailerModule in Users.Module and delete NodeMailerService from Users.Module.

Nest can't resolve dependencies of the BlahService although it is Global()

I have an issue with NestJS and it appears to be for just 1 module and all the others work fine. I have the following modules.
The error is:
[ExceptionHandler] Nest can't resolve dependencies of the ApplicationService (ApplicationModel, AwsService, UserService, ?, JobService). Please make sure that the argument at index [3] is available in the ApplicationModule context.
The AgencyService is [3]. If I remove the AgencyModule from the ApplicationModule NestJS successfully compiles and I can make API calls.
AgencyModule,
ApplicationModule,
AuthModule,
JobModule,
UserModule,
All these modules are required by other modules for their service providers so rather than import them between each other using forwardRef() I just made them Global() - May not be best practice but hey ho (it works).
My AppModule file.
#Module({
imports: [
MongooseModule.forRootAsync({
useFactory: (configService: ConfigService) => ({
uri: configService.get('MONGO_DB_URL'),
useNewUrlParser: true,
}),
imports: [ConfigModule],
inject: [ConfigService],
}),
ConfigModule,
AgencyModule,
ApplicationModule,
AuthModule,
DevModule,
JobModule,
UserModule,
VideoModule,
],
controllers: [AppController],
providers: [AppService],
})
export class AppModule {}
Each module folder has the following structure.
agency/
- dto/
- agency.controller.ts
- agency.interface.ts
- agency.schema.ts
- agency.service.ts
- agency.module.ts
My AgencyModule file.
#Global()
#Module({
imports: [
SharedModule,
MongooseModule.forFeature([{ name: 'Agency', schema: AgencySchema }]),
],
controllers: [
AgencyController,
],
providers: [
AgencyService,
AwsService,
],
exports: [
AgencyService,
],
})
export class AgencyModule implements NestModule {
public configure(consumer: MiddlewareConsumer) {
consumer
.apply()
.forRoutes(
{ path: 'agency', method: RequestMethod.GET },
);
}
}
My AgencyService file.
#Injectable()
export class AgencyService {
constructor(
#InjectModel('Agency') private readonly agencyModel: Model<Agency>,
private readonly awsService: AwsService,
private readonly applicationService: ApplicationService,
) {
//
}
// More stuff here but not worth adding to the snippet.
}
My ApplicationModule file.
#Global()
#Module({
imports: [
SharedModule,
MongooseModule.forFeature([{ name: 'Application', schema: ApplicationSchema }]),
],
controllers: [
ApplicationController,
],
providers: [
ApplicationService,
AwsService,
],
exports: [
ApplicationService,
],
})
export class ApplicationModule implements NestModule {
public configure(consumer: MiddlewareConsumer) {
consumer
.apply()
.forRoutes(
{ path: 'application', method: RequestMethod.GET },
);
}
}
My ApplicationService file.
#Injectable()
export class ApplicationService {
constructor(
#InjectModel('Application') private readonly applicationModel: Model<Application>,
private readonly awsService: AwsService,
private readonly userService: UserService,
private readonly agencyService: AgencyService,
private readonly jobService: JobService,
) {
//
}
// More stuff here but not worth adding to the snippet.
}
The AwsService is a shared service without a module.
Using #Global() does not automatically resolve circular dependencies, you still have to use #Inject(forwardRef(() => MyService)) on both sides, see the docs.
As you noted yourself, circular dependencies (forwardRef) and global modules (#Global) are bad style and should be avoided. Rather make your dependencies explicit. If you encounter a circular dependency extract the commonly used parts in a shared service/module that is imported by both sides, see this thread.

Pass variable to module using forRoot

I've developed a library with shared components in Angular and I want to pass configuration there.
Everything is basically the same as in:
Pass config data using forRoot
Problem is, that I need to pass user to this module, which is fetched on start of application and saved in Redux state.
Is it possible to pass observable with user using forRoot while importing module? Maybe it's possible to pass something to this module 'later' with some lazy loading?
#select() private user$: Observable<User>
#NgModule({
imports: [
LibModule.forRoot({
user: user$
})
...
})
I've made it another way - by injecting my implementation of abstract service for getting settings. Code below:
Lib module declaration:
export interface LibSettings {
user: User;
url: string;
}
export abstract class AbstractLibSettingsService {
abstract getSettings(): LibSettings;
}
#NgModule({
declarations: [...],
imports: [...],
exports: [...]
})
export class LibModule {
static forRoot(implementationProvider: Provider): ModuleWithProviders {
return {
ngModule: LibModule,
providers: [
implementationProvider
]
}
}
}
Lib service, where I needed the user:
constructor(private settingsService: AbstractGlassLibSettingsService) {
}
In application that uses the lib, module declaration with import:
export const LIB_SETTINGS_PROVIDER: ClassProvider = {
provide: AbstractLibSettingsService,
useClass: LibSettingsService
};
#NgModule({
imports: [...
LibModule.forRoot(LIB_SETTINGS_PROVIDER)
],
...
})
Finally, the implementation of the service in application:
#Injectable()
export class LibSettingsService extends AbstractLibSettingsService {
#select() private user$: Observable<User>;
private user: User;
constructor() {
super();
this.user$.subscribe(user => this.user = user);
}
public getSettings(): GlassLibSettings {
...
}

Nest can't resolve dependencies of guard wrapped inside a decorator

I'm trying to inject a provider inside a guard that is wrapped in a decorator, but Nest is not being able to resolve dependencies, giving me the next error:
[ExceptionHandler] Nest can't resolve dependencies of the SecuredGuard (Reflector, ?). Please make sure that the argument at index [1] is available in the SecuredGuard context.
The main purpose of my approach is to avoid using two separate decorators like this:
#Controller()
export class AppController {
#Get()
#Secured('admin')
#UseGuards(SecuredGuard)
getHello(): string {
return this.appService.getHello();
}
}
And instead insert the #UseGuards(SecuredGuard) inside my custom decorator #Secured('admin') so it ends up like this:
#Controller()
export class AppController {
#Get()
#Secured('admin')
getHello(): string {
return this.appService.getHello();
}
}
This is how I'm implementing my custom decorator:
export function Secured(...roles: string[]){
const setMetadata = ReflectMetadata('roles', roles)
const setupGuard = UseGuards(SecuredGuard)
return (target: any, key?: string, descriptor?: any) => {
setMetadata(target, key, descriptor);
setupGuard(target, key, descriptor);
}
}
And this is my SecuredGuard, the AuthService is the dependency that couldn't be resolved:
#Injectable()
export class SecuredGuard implements CanActivate {
constructor(
private readonly _reflector: Reflector,
private readonly _authService: AuthService
) { }
async canActivate(context: ExecutionContext): Promise<boolean> {...}
}
Both secured.guard.ts and secured.decorator.ts are part of secured.module.ts
#Module({
imports: [
SecuredGuard,
AuthModule
],
exports: [
SecuredGuard
],
providers: [
AuthService
]
})
export class SecuredModule {}
Which is using the AuthService being exported from auth.module.ts
#Module({
controllers: [
AuthController
],
providers: [
AuthService
],
imports: [
EmailModule
],
exports: [
AuthService
]
})
export class AuthModule { }
And secured.module.ts is being imported by app.module.ts
#Module({
imports: [
SecuredModule
],
controllers: [
AppController
],
providers: [
AppService
],
})
export class AppModule { }
I don't know if I'm using the appropriate approach, or even if it's possible what I'm trying to do, any clues would be really appreciated!
In general, your solution seems to work, see this running example:
However, there are some mistakes in your module declarations:
1) In your AppModule, the AuthService is not available, since neither is the AuthModule imported directly or exported by the SecuredModule. That's why you're getting the error.
2) You don't have to declare your guards in any module, they will just be available globally. Only put modules in your imports array.
3) You're providing the AuthService multiple times, so you will have different instances of it. You should only provide it once and then only export (or re-export) your provider, but not provide it again.
4) ReflectMetadata was deprecated in v6; use SetMetadata instead.

Categories

Resources