Using ConfigService inside async provider nestjs - node.js

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],
})

Related

Inject ConfigService in sub module

I'm new with NestJS and trying to understand the patterns.
I configure ConfigModule to use config set in a specific folder. I want to use that ConfigModule in a submodule but It doesn't work.
I have an app.module
app.module.ts
#Module({
imports: [
ConfigModule.forRoot({
envFilePath: ['.env.local', '.env'],
isGlobal: true,
expandVariables: true,
load: [dbConfiguration, jwtConfiguration],
}),
DatabaseModule,
AuthModule,
UsersModule,
],
controllers: [AppController],
providers: [],
exports: [ConfigModule]
})
export class AppModule {
}
auth.module.ts
#Module({
imports: [
UsersModule,
PassportModule,
ConfigModule,
JwtModule.registerAsync({
imports: [ConfigModule],
useFactory: async (configService: ConfigService) => ({
secretOrPrivateKey: configService.get('jwt').secret,
signOptions: {
expiresIn: 3600,
},
}),
inject: [ConfigService],
}),
],
providers: [AuthService, JwtStrategy],
exports: [AuthService]
})
export class AuthModule {}
jwt.strategy.ts
import { PassportStrategy } from "#nestjs/passport";
import { ExtractJwt, Strategy } from "passport-jwt";
import {ConfigService} from "#nestjs/config";
export class JwtStrategy extends PassportStrategy(Strategy) {
constructor(configService: ConfigService) {
console.log(configService);
super({
jwtFromRequest: ExtractJwt.fromAuthHeaderAsBearerToken(),
ignoreExpiration: false,
secretOrKey: configService.get('jwt').secret,
})
}
async validate(payload: any) {
return {userId: payload.sub, email: payload.email}
}
}
In the constructor, configService is undefined.
I import ConfigModule in auth.module that contain JwtStrategy.
What did I missed?
Missed the #Injectable() in JwtStrategy

Nestjs env variable with ClientsModuleOptions

I have the following IP and Ports but I want to carry this with environment variables so that they can be edited from there
import { ClientsModuleOptions, Transport } from "#nestjs/microservices"
export const GatewayOptions: ClientsModuleOptions = [
{
name: 'MICRO-ADMIN',
transport: Transport.TCP,
options: {
host: '127.20.20.2',
port: 4000,
},
},
{
name: 'MICRO-DEV',
transport: Transport.TCP,
options: {
host: '127.30.30.3',
port: 5000,
},
},
];
I import this configuration to the module.
import { Module } from '#nestjs/common';
import { ClientsModule } from '#nestjs/microservices';
import { GatewayOptions } from 'src/utils/gateway/gateway';
import { AuthModule } from './../auth/auth.module';
import { CategoryModule } from './../category/category.module';
import { GameController } from './game.controller';
import { GameService } from './game.service';
#Module({
imports: [
AuthModule,
CategoryModule,
ClientsModule.register(GatewayOptions)
],
controllers: [GameController],
providers: [GameService],
exports: [GameService],
})
export class GameModule {}
You need to use register async to use ConfigService
Follow the documentation: https://docs.nestjs.com/microservices/basics#client
#Module({
providers: [
{
provide: 'MATH_SERVICE',
useFactory: (configService: ConfigService) => {
const mathSvcOptions = configService.getMathSvcOptions();
return ClientProxyFactory.create(mathSvcOptions);
},
inject: [ConfigService],
}
]
...
})
Here is how you can configure the ConfigService: https://docs.nestjs.com/techniques/configuration#configuration

How to initialize on nestjs module multiple times with different configurations?

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

NestJS ConfigService returns undefined values during async TypeORM configuration on app startup

I'm trying to setup configuration for my NestJS app by following some of the following documentation:
Config: https://docs.nestjs.com/techniques/configuration
TypeORM: https://docs.nestjs.com/techniques/database#async-configuration
I've added a .env file to the root of my project (same level as package.json) with the following values:
DB_URL=localhost
DB_USER=root
DB_PASSWORD=root
DB_NAME=test_db
In my app.module.ts, I import the following modules:
import { Module } from '#nestjs/common';
import { TypeOrmModule } from '#nestjs/typeorm';
import { ConfigModule, ConfigService } from '#nestjs/config';
import { AppController } from './app.controller';
import { AppService } from './app.service';
#Module({
imports: [
ConfigModule.forRoot(),
TypeOrmModule.forRootAsync({
imports: [ConfigModule],
useFactory: (configService: ConfigService) => {
// The value logged below is undefined'
console.log(`DB URL: ${configService.get('DB_URL')}`);
return {
type: 'mysql',
host: configService.get('DB_URL'),
port: 3306,
username: configService.get('DB_USER'),
password: configService.get('DB_PASSWORD'),
database: configService.get('DB_NAME'),
entities: ['dist/**/*.entity{.ts,.js}'],
synchronize: false,
migrations: ['dist/migrations/*{.js}'],
cli: {
migrationsDir: 'migrations',
},
};
},
inject: [ConfigService],
}),
],
controllers: [AppController],
providers: [AppService],
})
export class AppModule {}
As noted above, the value retrieved by configService.get('DB_URL') is undefined. Was hoping for any help/advice on how to set up the configuration so that I could read the values in my .env file when starting up the application.

NestJS - Use multiple MongoDB connections per module

Is there a way to connect multiple MongoDB connections per module?
app.module.ts
#Module({
imports: [
MongooseModule.forRoot('mongodb://localhost/masterDB'),
UserModule,
],
controllers: [AppController],
providers: [AppService],
})
export class AppModule { }
Similarly, can we define another connection in another module which is a child of app.module?
child.module.ts
#Module({
imports: [
MongooseModule.forRoot('mongodb://localhost/childDB'),
MongooseModule.forFeature([{ name: 'child', schema: ChildSchema }]),
],
controllers: [ChildController],
providers: [ChildService],
})
export class ChildModule { }
Or any other way to access different databases at once.
Thanks in advance!
[SOLVED March 2021]
Here you'll find the solution:
https://www.learmoreseekmore.com/2020/04/nestjs-multiple-mongodb-databases.html
import { Module } from '#nestjs/common';
import { MongooseModule } from '#nestjs/mongoose';
import { studentSchema } from './schemas/myworld/student.schema';
import { animalSchema } from './schemas/wildlife/animal.schema';
#Module({
imports: [
MongooseModule.forFeature([
{
name: 'Student',
schema: studentSchema,
collection: 'Student',
},
],'myWorldDb'),
MongooseModule.forFeature([
{
name: 'Animals',
schema: animalSchema,
collection: 'Animals'
}
],'wildLifeDb'),
MongooseModule.forRoot(
'mongodb+srv://<userName>:<password>#cluster0-igk.mongodb.net/MyWorld?retryWrites=true&w=majority',
{
connectionName: 'myWorldDb'
}
),
MongooseModule.forRoot(
'mongodb+srv://<username>:<password>#cluster0-igk.mongodb.net/WildLife?retryWrites=true&w=majority',
{
connectionName: 'wildLifeDb'
}
)
],
controllers: [],
providers: [],
})
export class AppModule {}
You have to do it manually you have to use a providers file:
mongoose.providers.ts
import * as mongoose from 'mongoose';
export const mongooseProviders = [
{
provide: 'MASTER_CONNECTION',
useFactory: (): Promise<typeof mongoose> =>
// This mongoose.connect never working for multples DB connection
// mongoose.connect('mongodb://localhost/masterDB'),
// Following is working fine and tested by me
mongoose.createConnection('mongodb://localhost/masterDB'),
},
{
provide: 'CHILD_CONNECTION',
useFactory: (): Promise<typeof mongoose> =>
// This mongoose.connect never working for multples DB connection
// mongoose.connect('mongodb://localhost/masterDB'),
// Following is working fine and tested by me
mongoose.createConnection('mongodb://localhost/ChildDB'),
},
];
mongoose.module.ts
import { Module } from '#nestjs/common';
import { mongooseProviders } from './mongoose.providers';
#Module({
providers: [...mongooseProviders],
exports: [...mongooseProviders],
})
export class MongooseModule {}
model.providers.ts
import { Connection } from 'mongoose';
import { ChildSchema } from './schemas/child/child.schema';
import { MasterSchema } from './schemas/master/master.schema';
export const modelProviders = [
{
provide: 'CHILD_MODEL',
useFactory: (connection: Connection) => connection.model('Child', ChildSchema),
inject: ['CHILD_CONNECTION'],
},
{
provide: 'MASTER_MODEL',
useFactory: (connection: Connection) => connection.model('Master', MasterSchema),
inject: ['MASTER_CONNECTION'],
},
];
And on the constructor instead of using #InjectModel you use #Inject:
#Injectable
export Class ModelService {
constructor(#Inject('MASTER_MODEL') private masterModel: Model<Master>) {}
...
Note: in the module you provide the service you should import the MongooseModule and put as provider modelProviders.
Post above from RalphJS really helped, but it only was using one connection for everything. Had to change 1 thing in model.providers.ts:
instead of mongoose.connect
you have to use mongoose.createConnection
model.providers.ts
import * as mongoose from 'mongoose';
export const mongooseProviders = [
{
provide: 'MASTER_CONNECTION',
useFactory: async (): Promise<unknown> =>
await mongoose.createConnection('mongodb://localhost/masterDB'),
},
{
provide: 'CHILD_CONNECTION',
useFactory: async (): Promise<unknown> =>
await mongoose.createConnection('mongodb://localhost/childDB'),
},
];
https://mongoosejs.com/docs/connections.html#multiple_connections

Resources