import { NgModule} from '#angular/core';
import { LibChildComponent } from './lib-child.component';
import { ModuleWithProviders } from '#angular/compiler/src/core';
import { LibParentModule } from 'lib-parent';
#NgModule({
imports: [
LibParentModule.forRoot(CONFIG)
],
declarations: [LibChildComponent],
exports: [LibChildComponent]
})
export class LibChildModule {
static forRoot(configs: any): ModuleWithProviders {
return {
ngModule: LibChildModule,
providers: [
{
provide: 'LIB_CONFIG',
useValue: configValues,
}
]
};
}
}
I want to pass the config data from child module to parent module. when data set to child's forRoot method then it should set to parent's forRoot method.
How can i do that? Is there anybody help me it will be more helpful.
Related
#Module({
imports: [],
providers: [SupertokensService, AuthService],
exports: [],
controllers: [AuthController],
})
export class AuthModule implements NestModule {
configure(consumer: MiddlewareConsumer) {
consumer.apply(AuthMiddleware).forRoutes('*');
}
static forRoot({
connectionURI,
apiKey,
appInfo,
}: AuthModuleConfig): DynamicModule {
return {
providers: [
{
useValue: {
appInfo,
connectionURI,
apiKey,
},
provide: ConfigInjectionToken,
},
],
exports: [],
imports: [],
module: AuthModule,
};
}
}
The problem with this implementaion I can't use env variables, so I need useFactory to pass ConfigService. Can somebody do that, and give some explanation.
I figure out how to make this work, unfortunately it only works with nest.js version 9 (current latest version). First you need to create a new file. For example auth.module-definition.ts. Now in this file we need to create ConfigurableModuleBuilder.
import { ConfigurableModuleBuilder } from '#nestjs/common';
import { AuthModuleConfig } from './config.interface';
export const { ConfigurableModuleClass, MODULE_OPTIONS_TOKEN } =
new ConfigurableModuleBuilder<AuthModuleConfig>()
.setClassMethodName('forRoot')
.build();
we need to set setClassMethodName('forRoot'), when we set forRoot it will create two methods, forRoot and forRootAsync. The next step is to extend our created ConfigurableModuleClass. it should look something like this
import { MiddlewareConsumer, Module } from '#nestjs/common';
import { AuthMiddleware } from './auth.middleware';
import { SupertokensService } from './supertokens/supertokens.service';
import { AuthController } from './auth.controller';
import { AuthService } from './auth.service';
import { ConfigurableModuleClass } from './auth.module-definition';;
#Module({
imports: [],
providers: [SupertokensService, AuthService],
controllers: [AuthController],
exports: [AuthService],
})
export class AuthModule extends ConfigurableModuleClass {
configure(consumer: MiddlewareConsumer) {
consumer.apply(AuthMiddleware).forRoutes('*');
}
}
And that's actually it, so from now on we have forRootAsync and we get reigister it in app.module.ts
import { MiddlewareConsumer, Module, NestModule } from '#nestjs/common';
import { AuthModule } from './auth/auth.module';
import { ConfigModule, ConfigType } from '#nestjs/config';
import authConfig from './auth/auth.config';
#Module({
imports: [
AuthModule.forRootAsync({
inject: [authConfig.KEY],
imports: [ConfigModule.forFeature(authConfig)],
useFactory: (config: ConfigType<typeof authConfig>) => {
return {
connectionURI: config.CONNECTION_URI,
appInfo: {
appName: config.appInfo.APP_NAME,
apiDomain: config.appInfo.API_DOMAIN,
websiteDomain: config.appInfo.WEBSITE_DOMAIN,
apiBasePath: config.appInfo.API_BASE_PATH,
websiteBasePath: config.appInfo.WEBSITE_BASE_PATH,
},
};
},
})
],
controllers: [],
providers: [
],
})
export class AppModule implements NestModule {
}
here I am using Nest.js Config, but you don't need to, so use it how you want.
I know that my english is not the best, so if you still do not understand you can check these sources https://docs.nestjs.com/fundamentals/dynamic-modules#configurable-module-builder
https://trilon.io/blog/nestjs-9-is-now-available#Configurable-module-builder
I have CurrencyService that I want to use in another module. Here's what I did:
import { HttpModule } from '#nestjs/axios';
import { Module } from '#nestjs/common';
import { ScheduleModule } from '#nestjs/schedule';
import { TypeOrmModule } from '#nestjs/typeorm';
import { CurrencyRepository } from './currency.repository';
import { CurrencyService } from './currency.service';
#Module({
imports: [
HttpModule,
ScheduleModule.forRoot(),
TypeOrmModule.forFeature([CurrencyRepository]),
],
exports: [CurrencyService],
providers: [CurrencyService],
})
export class CurrencyModule {}
In my CurrencyService, I have injected a repository and another service:
export class CurrencyService {
constructor(
private currencyRepository: CurrencyRepository,
private httpService: HttpService,
) {}
async getCurrency(base: string, target: string): Promise<Currency> {
console.log(this.currencyRepository);
.....
My problem is that when I import the CurrencyModule, and inject the CurrencyService into the service of another module, currencyRepository and httpService are both undefined.
There is no error on startup, it's just that the dependencies are undefined which causes error on runtime.
I also tried something like this:
import { HttpModule } from '#nestjs/axios';
import { Module } from '#nestjs/common';
import { ScheduleModule } from '#nestjs/schedule';
import { TypeOrmModule } from '#nestjs/typeorm';
import { CurrencyRepository } from './currency.repository';
import { CurrencyService } from './currency.service';
#Module({
imports: [
HttpModule,
ScheduleModule.forRoot(),
TypeOrmModule.forFeature([CurrencyRepository]),
],
exports: [
CurrencyService,
TypeOrmModule.forFeature([CurrencyRepository]),
HttpModule,
],
providers: [CurrencyService],
})
export class CurrencyModule {}
I got the same undefined dependencies.
The #Injectable() decorator is missing from the CurrencyService. This decorator (or any decorator really) is what tells Typescript to emit the metadata of the controller that Nest is reading, so it is crucial to have it in place.
I created my Dynamic configModule to extract environment variables from a different path. It extracts from an yml file. Everything works properly if a add in some module. Here is my ConfigModule:
import { DynamicModule } from '#nestjs/common';
import { ConfigModule } from '#nestjs/config';
import { EnvConfigService } from './env.config.service';
export class EnvConfigModule {
/**
* Create an static function to call directly from the class without instantiation
* #param options: Our config module attributes or properties
* #returns DynamicModule
*/
static register(options): DynamicModule {
return {
module: ConfigModule,
providers: [
{
provide: 'CONFIG_OPTIONS',
useValue: options,
},
EnvConfigService,
],
exports: [EnvConfigService],
};
}
}
Now when I want to add that configuration in the new custom JwtModule, CustomJwtModule:
...
import { EnvConfigModule } from 'src/utils/environment/env.config.module';
import { EnvConfigService } from 'src/utils/environment/env.config.service';
#Module({
imports: [
JwtModule.registerAsync({
imports: [EnvConfigModule],
inject: [EnvConfigService],
useFactory: (configService: EnvConfigService) => {
const base64_pubKey = configService.get(ACCESS_PUBLIC_KEY_NAME);
return {
publicKey: Buffer.from(base64_pubKey, KEY_ENCODING),
signOptions: {
algorithm: ENCRYPTION_ALGORITHM,
},
};
},
}),
],
providers: [
{
provide: JWT_ACCESS_SERVICE,
useExisting: JwtService,
},
],
exports: [JWT_ACCESS_SERVICE],
})
export class JWTAccessModule {}
And here is my error:
Error: Nest can't resolve dependencies of the JWT_MODULE_OPTIONS (?). Please make sure that the argument EnvConfigService at index [0] is available in the JwtModule context.
I guess, I do get that error because it does not inject properly in JWT module my service.
My app.module.ts is implemented in that way
...
import { EnvConfigModule } from './utils/environment/env.config.module';
#Module({
imports: [
IamModule,
EnvConfigModule.register({
folder: 'config/environment/',
}),
],
controllers: [AppController],
providers: [AppService],
})
export class AppModule {}
Ok, it seems I was importing wrongly. It was missing some part of the configuration. Here is the working example of CustomJwtModule:
...
import { EnvConfigModule } from 'src/utils/environment/env.config.module';
import { EnvConfigService } from 'src/utils/environment/env.config.service';
#Module({
imports: [
JwtModule.registerAsync({
imports: [EnvConfigModule.register({
folder: 'config/environment/',
}),
],
inject: [EnvConfigService],
...
I have trouble with using mongoose in nest
error message is below :
Nest can't resolve dependencies of the movieModel (?). Please make sure that the argument DatabaseConnection at index [0] is available in the MongooseModule context.
Potential solutions:
If DatabaseConnection is a provider, is it part of the current MongooseModule?
If DatabaseConnection is exported from a separate #Module, is that module imported within MongooseModule?
movies.service.ts
import { Injectable } from '#nestjs/common';
import { CreateMovieDto } from './dto/create-movie.dto';
import { InjectModel } from '#nestjs/mongoose';
import { movie, movieDocument } from './schema/movie.schema';
import { Model } from 'mongoose';
#Injectable()
export class MoviesService {
constructor(
#InjectModel(movie.name) private movieModel: Model<movieDocument>,
) {}
async create(CreateMovieDto: CreateMovieDto): Promise<movie> {
return new this.movieModel(CreateMovieDto).save();
}
async getAll(): Promise<movie[]> {
return this.movieModel.find().exec();
}
app.modules.ts
import { Module } from '#nestjs/common';
import { MongooseModule } from '#nestjs/mongoose';
import { MoviesModule } from './movies/movies.module';
#Module({
imports: [
MoviesModule,
MongooseModule.forRoot('mongodb://localhost:27017/databasename', {
connectionName: 'movies',
}),
],
controllers: [],
providers: [],
})
export class AppModule {}
movie.module.ts
import { Module } from '#nestjs/common';
import { MongooseModule } from '#nestjs/mongoose';
import { MoviesController } from './movies.controller';
import { MoviesService } from './movies.service';
import { movieSchema } from './schema/movie.schema';
#Module({
imports: [
MongooseModule.forFeature([
{
name: 'movie',
schema: movieSchema,
collection: 'movies',
},
]),
],
controllers: [MoviesController],
providers: [MoviesService], //nestjs가 movieservice를 import하고 controller에 inject 한다.
})
export class MoviesModule {}
please help me figure this out
I have created an interceptor as shown below that I wish to use globally. I added the interceptor to my module and set it up so that nest js should handle the DI for me per NestJS Docs, however when I make a request to my service, I get an error indicating Cannot read property log of undefined so it appears that the DI is not being taken care of by NestJS.
Interceptor Code:
import { Injectable, NestInterceptor, ExecutionContext, CallHandler } from '#nestjs/common';
import { Observable } from 'rxjs';
import { map } from 'rxjs/operators';
import { LoggingService } from './logging.service';
#Injectable()
export class AuthInterceptor implements NestInterceptor {
constructor(private readonly loggingService: LoggingService) { }
intercept(context: ExecutionContext, next: CallHandler): Observable<any> {
return next
.handle()
.pipe(
map((response) => {
this.loggingService.log('Responded successfully');
return response;
})
);
}
}
Interceptor Module:
import { Module } from '#nestjs/common';
import { APP_INTERCEPTOR } from '#nestjs/core';
import { AuthInterceptor } from './auth.interceptor';
import { LoggingService } from './logging.service';
#Module({
providers: [
LoggingService,
{
provide: APP_INTERCEPTOR,
useClass: AuthInterceptor,
},
],
})
export class AuthInterceptorModule {}
My app.module.ts at the root of my application imports the AuthInterceptorModule. I am assuming I am messing something up but it is not clear to me how to fix this DI issue.
I was able to resolve this one on my own after finding that my LoggingService relied on another dependency that was request scoped. Since there was a request scoped dependency in my interceptor, this meant that my interceptor also had to be request scoped.
The change to the code was simple and only required that I change the AuthInterceptorModule from:
import { Module } from '#nestjs/common';
import { APP_INTERCEPTOR } from '#nestjs/core';
import { AuthInterceptor } from './auth.interceptor';
import { LoggingService } from './logging.service';
#Module({
providers: [
LoggingService,
{
provide: APP_INTERCEPTOR,
useClass: AuthInterceptor,
},
],
})
export class AuthInterceptorModule {}
to
import { Module } from '#nestjs/common';
import { APP_INTERCEPTOR, Scope } from '#nestjs/core';
import { AuthInterceptor } from './auth.interceptor';
import { LoggingService } from './logging.service';
#Module({
providers: [
LoggingService,
{
provide: APP_INTERCEPTOR,
scope: Scope.REQUEST,
useClass: AuthInterceptor,
},
],
})
export class AuthInterceptorModule {}