How can I create two or multiple instances of a nestjs module? E.g. we would like to have two different instances of the TwilioModule and use different configurations for them.
import { TwilioModule } from 'nestjs-twilio';
#Module({
imports: [
TwilioModule.forRootAsync({
imports: [ConfigModule],
useFactory: async (cfg: ConfigService) => ({
accountSid: cfg.get('TWILIO_ACCOUNT_SID'),
authToken: cfg.get('TWILIO_AUTH_TOKEN'),
}),
inject: [ConfigService],
}),
TwilioModule.forRootAsync({
imports: [ConfigModule],
useFactory: async (cfg: ConfigService) => ({
accountSid: cfg.get('TWILIO_ACCOUNT_SID_2'),
authToken: cfg.get('TWILIO_AUTH_TOKEN_2'),
}),
inject: [ConfigService],
}),
],
})
export class AppModule {}
Hey for this the package needs to have this feature.
I recommend this.
import { Twilio } from 'twilio';
providers: [
{
provide: 'twilio1',
useFactory: () => {
return new Twilio('ACasd', 'wasdsa');
},
},
{
provide: 'twilio2',
useFactory: () => {
return new Twilio('ACasd', 'wasdsa');
},
},
]
Use the following in the controller or in service
#Inject("twilio1") t1 : Twilio
Example:-
constructor(#Inject('twilo1') t1: Twilio) {}
read more # https://docs.nestjs.com/fundamentals/custom-providers#factory-providers-usefactory
Related
I need to use the ConfigService to get the environment variables, but when I use "forRootAsync" of the TypeOrmModule nestjs is unable to resolve the DataService dependency
This is my module
#Module({
imports: [
ConfigModule.forRoot({ validate: validateConfig(AssetEnvironmentVariables), isGlobal: true }),
TypeOrmModule.forRootAsync({
imports: [ConfigModule],
inject: [ConfigService],
useFactory: (configService: ConfigService): TypeOrmModuleOptions => ({
type: "postgres",
host: configService.get("PG_HOST"),
port: configService.get("PG_PORT"),
database: configService.get("PG_DB_NAME"),
username: configService.get("PG_USER"),
password: configService.get("PG_PASSWORD"),
entities: [AssetEntity],
migrations: ["./migrations/*"],
}),
});
],
providers: [
{ provide: AssetRepository, useClass: AssetPostgresRepository },
],
})
export class AssetModule {}
This is the implementation to AssetRepository
#Injectable()
export class AssetPostgresRepository extends AssetRepository {
private typeOrmRepository: Repository<AssetEntity>;
constructor(dataSource: DataSource) {
super();
this.typeOrmRepository = dataSource.getRepository(AssetEntity);
}
async save(asset: Asset): Promise<void> {
try {
await this.typeOrmRepository.save(asset.toPrimitives());
} catch (e) {
throw new SavingRepositoryException(e);
}
}
}
This is the error that it throw me
ERROR [ExceptionHandler] Nest can't resolve dependencies of the AssetPostgresRepository (?). Please make sure that the argument DataSource at index [0] is available in the AssetModule context.
Potential solutions:
- Is AssetModule a valid NestJS module?
- If DataSource is a provider, is it part of the current AssetModule?
- If DataSource is exported from a separate #Module, is that module imported within AssetModule?
#Module({
imports: [ /* the Module containing DataSource */ ]
})
This code is to integrate NestJs on sentry .
**SentryModule.forRootAsync({
imports: [ConfigModule],
useFactory: async (configService: ConfigService) => ({
dsn: configService.get<string>('sentry.dsn'),
debug: true,
environment: configService.get<string>('sentry.env'),
logLevels: ['error'],
}),
inject: [ConfigService],
})
],
providers: [
{
provide: APP_INTERCEPTOR,
useValue: new SentryInterceptor(),
},
],
controllers: [AppController],
})
export class AppModule {}**
I need to integrate performance monitoring in NestJs on sentry.
There are plenty of articles showing how to inject providers into dynamic module but all of them only show examples using their exported services, none with middleware. Using the exact same method as used with services for middleware fails. How can I create reusable middleware that requires providers to be injected?
Example middleware, requiring injection of a UserService provider
#Injectable()
export class AuthMiddleware implements NestMiddleware {
constructor(#Inject(USER_SERVICE) private readonly userService: UserService) {
console.log('userService findAll: ', userService.findAll());
}
use(req: any, res: any, next: () => void) {
console.log('AuthMiddleware called!');
next();
}
}
Example module containing the middleware:
#Module({
providers: [AuthService, AuthMiddleware],
imports: [ExtModule],
})
export class AuthModule extends createConfigurableDynamicRootModule<
AuthModule,
AuthModuleOptions
>(AUTH_OPTIONS, {
providers: [
{
provide: AUTH_SECRET,
inject: [AUTH_OPTIONS],
useFactory: (options: AuthModuleOptions) => options.secret,
},
{
provide: USER_SERVICE,
inject: [AUTH_OPTIONS],
useFactory: (options: AuthModuleOptions) => options.userService,
},
],
controllers: [AuthController],
}) {}
Now importing the module and trying to use the middleware:
#Module({
imports: [
ConfigModule.forRoot(),
AuthModule.forRootAsync(AuthModule, {
imports: [ConfigModule, UserModule],
inject: [ConfigService, UserService],
useFactory: (config: ConfigService, userService: UserService) => {
return {
secret: config.get('AUTH_SECRET_VALUE'),
userService,
};
},
}) as DynamicModule,
UserModule,
],
controllers: [UserController],
providers: [],
})
export class AppModule implements NestModule {
configure(consumer: MiddlewareConsumer) {
consumer.apply(AuthMiddleware).forRoutes('*');
}
}
Now when initializing the AuthModule dependencies the middleware class is clearly instantiated correctly, the userService.findAll being logged:
userService findAll: []
So far so good, and this works fine for services.
But the problem is that when then actually using the middleware in configure(), the injected context is not used
...\app\node_modules\#nestjs\core\injector\injector.js:193
throw new unknown_dependencies_exception_1.UnknownDependenciesException(wrapper.name, dependencyContext, moduleRef);
^
Error: Nest can't resolve dependencies of the class AuthMiddleware {
constructor(userService) {
this.userService = userService;
console.log('userService findAll: ', userService.findAll());
}
use(req, res, next) {
console.log('AuthMiddleware called!');
next();
}
} (?). Please make sure that the argument Symbol(USER_SERVICE) at index [0] is available in the AppModule context.
I've ended up getting it to work, mostly by re-exporting the injected providers. After trying different combinations, the working one is as follows
Static dependencies (e.g. external libraries) need to be imported and re-exported inside the module decorator
Dynamic dependencies need to be imported and re-exported inside createConfigurableDynamicRootModule
Exporting the Middleware class seems to have no effect in any way
#Module({
providers: [],
imports: [ExtModule],
exports: [ExtModule],
})
export class AuthModule extends createConfigurableDynamicRootModule<
AuthModule,
AuthModuleOptions
>(AUTH_OPTIONS, {
providers: [
{
provide: AUTH_SECRET,
inject: [AUTH_OPTIONS],
useFactory: (options: AuthModuleOptions) => options.secret,
},
{
provide: USER_SERVICE,
inject: [AUTH_OPTIONS],
useFactory: (options: AuthModuleOptions) => options.userService,
},
],
exports: [
{
provide: AUTH_SECRET,
inject: [AUTH_OPTIONS],
useFactory: (options: AuthModuleOptions) => options.secret,
},
{
provide: USER_SERVICE,
inject: [AUTH_OPTIONS],
useFactory: (options: AuthModuleOptions) => options.userService,
},
],
}) {}
I want to know if it possible to inject ConfigService into module import:
import { Module } from '#nestjs/common';
import { FileService } from './file.service';
import { FileResolver } from './file.resolver';
import { FileUploadController } from './contollers/file-upload.controller';
import { S3Service } from './host/s3.service';
import { AwsSdkModule } from 'nest-aws-sdk';
import { S3, SharedIniFileCredentials } from 'aws-sdk';
#Module({
controllers: [FileUploadController],
providers: [FileService, FileResolver, S3Service],
exports: [FileService, FileResolver],
imports: [
ConfigService.forRoot(),
AwsSdkModule.forRoot({
// use config service here
// configService.get('some-value')
defaultServiceOptions: {
region: 'us-east-1',
credentials: new SharedIniFileCredentials({
profile: 'my-profile',
}),
},
services: [S3],
}),
],
})
export class StorageModule {}
is it possible to use the configService inside AwsSdkModule provider?
Maybe you could try
AwsSdkModule.forRootAsync({
imports: [ConfigService],
inject: [ConfigService],
useFactory: (configService: ConfigService) {
}
})
You can try this.
AwsSdkModule.forRootAsync({
defaultServiceOptions: {
inject: [ConfigService],
useFactory: (configService: ConfigService) => ({
region: configService.get('region'),
credentials: {
accessKeyId: configService.get('access_key'),
secretAccessKey: configService.get('secret_key'),
},
}),
},
services: [S3],
})
I am working on a nestjs project using Kafka microservices (import from #nestjs/microservices).
for listening to a message, I am using the following code in main.ts:
const app = await NestFactory.createMicroservice<MicroserviceOptions>(
AppModule,
{
imports: [ConfigModule],
useFactory: async (configService: ConfigService) => ({
transport: Transport.KAFKA,
options: {
client: {
brokers: configService.get('brokers'),
},
},
}),
inject: [ConfigService],
},
);
await app.listen();
I am trying to let the nestjs read brokers from .env.
It can not work.
and I got error :
Argument of type '{ imports: (typeof ConfigModule)[]; useFactory: (configService: ConfigService) => Promise<{ transport: Transport; options: { client: { brokers: any; }; }; }>; inject: (typeof ConfigService)[]; }' is not assignable to parameter of type 'NestApplicationContextOptions & MicroserviceOptions'.
Object literal may only specify known properties, and 'imports' does not exist in type 'NestApplicationContextOptions & MicroserviceOptions'.
if delete 'imports: [ConfigModule]', I have the following error:
Argument of type '{ useFactory: (configService: ConfigService) => Promise<{ transport: Transport; options: { client: { brokers: any; }; }; }>; inject: (typeof ConfigService)[]; }' is not assignable to parameter of type 'NestApplicationContextOptions & MicroserviceOptions'.
Object literal may only specify known properties, and 'useFactory' does not exist in type 'NestApplicationContextOptions & MicroserviceOptions'.
Please help :)
as I see that you included config module at root level, and you did not initialize it. I think you should add Config Module like below.
imports: [
ConfigModule.forRoot({
isGlobal: true,
}),
someModule,
fooModule,
],
useFactory: async (configService: ConfigService) => ({
transport: Transport.KAFKA,
options: {
client: {
brokers: configService.get('brokers'),
},
},
}),
inject: [ConfigService],
})