I followed the the Nest documentation to create the config but it's not working
app.module.ts
#Module({
imports: [
ConfigModule.forRoot({ isGlobal: true }),
TypeOrmModule.forRoot(config),
AuthModule,
UsersModule,
MailModule,
CloudinaryModule,
],
controllers: [AppController],
providers: [AppService],
})
.env file is on the src folder
mail.module.ts
#Module({
imports: [
MailerModule.forRoot({
transport: {
service: 'Gmail',
auth: {
user: process.env.MAIL_USER,
pass: process.env.MAIL_PASS,
},
},
}),
],
But when I run the app its undefined my key value pairs are also there.
The problem is ConfigModule's env variables are only available at run time but not on the nestjs initial state.
To allow getting the .env after nestjs initialised, you can use async config to in MailerModule.
mail.config.ts
export class MailerConfig implements MailerOptionsFactory {
createMailerOptions(): MailerOptions | Promise<MailerOptions> {
console.log(process.env.MAIL_USER); // should have value
return {
transport: {
service: 'Gmail',
auth: {
user: process.env.MAIL_USER,
pass: process.env.MAIL_PASS,
},
},
};
}
}
mail.module.ts
console.log(process.env.MAIL_USER); // undefined
#Module({
imports: [
MailerModule.forRootAsync({
useClass: MailerConfig,
}),
],
})
export class MailModule {}
you can use useFactory as well without the need of class, here I want to console.log the .env for you to check with so i used config class.
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 */ ]
})
I am learning NestJS and I am trying to test a service which incorporates a repository with TypeORM. It compiles fine without errors, but when I run the test it throw an error.
I know it is a test dependency problem but I can't figure it out. I am trying this test:
describe('JokesService', () => {
let service: JokesService;
beforeEach(async () => {
const module: TestingModule = await Test.createTestingModule({
providers: [],
imports: [
TypeOrmModule.forFeature([JokeEntity])
],
}).compile();
service = module.get<JokesService>(JokesService);
});
it('should be defined', () => {
expect(service).toBeDefined();
});
});
The module:
#Module({
providers: [JokesService],
imports: [
TypeOrmModule.forFeature([JokeEntity])
],
controllers: [JokesController],
})
export class JokesModule {}
The service:
#Injectable()
export class JokesService {
constructor(
#InjectRepository(JokeEntity)
private readonly jokeRepository: MongoRepository<JokeEntity>
) {}
}
The main module:
#Module({
imports: [
TypeOrmModule.forRoot({
type: 'mongodb',
url: dbUri,
entities: [__dirname + '/**/*.entity{.ts,.js}'],
ssl: true,
useUnifiedTopology: true,
useNewUrlParser: true,
}),
JokesModule
],
controllers: [AppController],
providers: [AppService],
})
export class AppModule {}
And the error:
Nest cant resolve dependencies of the JokeEntityRepository (?).
Please make sure that the argument Connection at index [0] is available in the TypeOrmModule context.
Potential solutions:
- If Connection is a provider, is it part of the current TypeOrmModule?
- If Connection is exported from a separate #Module, is that module imported within TypeOrmModule?
#Module({
imports: [ /* the Module containing Connection */ ]
})
Can someone tell me what I am missing in the test dependencies? Thank You.
Try to import your JokesModule inside your app.module.
#Module({
imports: [
TypeOrmModule.forRoot({
type: 'mongodb',
url: dbUri,
entities: [__dirname + '/**/*.entity{.ts,.js}'],
ssl: true,
useUnifiedTopology: true,
useNewUrlParser: true,
}),
JokesModule,
],
controllers: [AppController],
providers: [AppService],
})
export class AppModule {}
I am new to nestJS and I want to setup .env for existing application & facing issue.
I have custom provider for appModule as below,
#Module({
providers: [
AbcService,
XyzService,
],
imports: [
TypeOrmModule.forRoot({
type: 'mysql',
host: 'xxxxxxxx',
port: 3230,
username: 'xyz',
password: 'password',
database: 'xyz-db',
entities: [__dirname + '/entities/**/*.entity{.ts,.js}'],
synchronize: true,
migrationsRun: true,
logging: true,
}),
TypeOrmModule.forFeature([
Transaction,
Payment,
]),
KafkaModule.forRoot(serviceConfig),
],
exports: [],
controllers: [ServiceSubscriptionController],
})
export class TopicModule { }
I have imported it inside AppModule as below,
#Module({
imports: [TopicModule],
controllers: [AppController],
providers: [AppService],
})
export class AppModule {}
I want to keep these stuff inside .env and I tried it as per documentation as below,
TypeOrmModule.forRootAsync({
imports: [ConfigModule.forRoot({
envFilePath: '.env',
})],
useFactory: async (configService: ConfigService) => {
return {
host: configService.get('HOST'),
type: 'mysql',
port: 3230,
username: 'xyz',
password: 'password',
database: 'xyz-db',
entities: [__dirname + '/entities/**/*.entity{.ts,.js}'],
synchronize: true,
migrationsRun: true,
logging: true,
}
},
inject: [ConfigService]
}),
I have .env at root path with HOST key-value pair as below but it read undefined from it.
In package.json,
"start": "nest start",
"start:dev": "nest start --watch",
It seems that Nest's ConfigModule will run fs.readFileSync(envFilePath) if you pass a file path to the forRoot() method. If you want it to read from the root directory, either remove the envFilePath option, or set the full file path, from your user's home directory.
I have loaded config in main.ts manually as below.
import { config } from 'dotenv';
async function bootstrap() {
//factory method for normal TS app
await config();
const app = await NestFactory.create(AppModule);
Now I can access it as,
configService.get('HOST') // as provided in question
or as process.env.HOST
Note: I have to use forRootAsync instead of forRoot to access process.env
I've recently converted my AppModule to a dynamic module so that I'm able to provide different configurations to MikroOrm depending on context (E2E tests, etc) and it currently looks like this:
#Module({
imports: [
MikroOrmModule.forFeature({
entities: [Todo],
}),
],
providers: [TodoService],
controllers: [AppController, TodosController],
})
export class AppModule {
static register(options?: {
mikroOrmOptions?: MikroOrmModuleOptions;
}): DynamicModule {
return {
module: AppModule,
imports: [
MikroOrmModule.forRoot({
entities: [Todo],
type: 'postgresql',
host: process.env.DB_HOST,
port: process.env.DB_PORT ? parseInt(process.env.DB_PORT) : 5432,
user: process.env.DB_USER,
password: process.env.DB_PASS,
dbName: process.env.DB_DB,
...options?.mikroOrmOptions,
}),
],
};
}
}
Now I'm trying to ensure graceful shutdown of the app by disconnecting from the database, but not sure where to place a life-cycle hook in this case. It doesn't seem to be possible to have a dynamic module with life-cycle hooks, so I'm thinking of developing a separate provider that injects the orm and write the hook on that.
What would be the correct approach? Thanks.
Edit:
I came up with the following solution. Would appreciate someone indicating if this is the best way:
import { MikroORM } from 'mikro-orm';
...
#Module({
imports: [
MikroOrmModule.forFeature({
entities: [Todo],
}),
],
providers: [TodoService],
controllers: [AppController, TodosController],
})
export class AppModule implements OnModuleDestroy {
static register(options?: {
mikroOrmOptions?: MikroOrmModuleOptions;
}): DynamicModule {
return {
module: AppModule,
imports: [
MikroOrmModule.forRoot({
entities: [Todo],
type: 'postgresql',
host: process.env.DB_HOST,
port: process.env.DB_PORT ? parseInt(process.env.DB_PORT) : 5432,
user: process.env.DB_USER,
password: process.env.DB_PASS,
dbName: process.env.DB_DB,
...options?.mikroOrmOptions,
}),
],
};
}
constructor(private orm: MikroORM) {}
async onModuleDestroy(): Promise<void> {
await this.orm.close();
}
}
As discussed in the issues, I would go with the way nestjs/typeorm is using, so using onApplicationShutdown hook.
Also linking the issue here for possible future readers:
https://github.com/dario1985/nestjs-mikro-orm/issues/10
I am following doc to start to use queue. I installed #nestjs/bull, bull, #types/bull dependencies. And here is my app.module.ts:
#Module({
imports: [
ConfigModule.forRoot({
load: [configuration],
}),
BullModule.registerQueue({
name: 'create_checkin',
redis: {
host: 'localhost',
port: 6379,
},
}),
EventModule,
],
})
export class AppModule {}
I imported BullModule in root module. And here is my event.service.ts:
#Injectable()
export class EventService {
constructor(
#InjectQueue('create_checkin') private readonly createCheckinQueue: Queue,
) {
}
}
And when I start server, I got the following error message:
Nest can't resolve dependencies of the EventService
Please make sure that the argument BullQueue_create_checkin at index [0] is available in the EventModule context.
I don't know which step I did wrong. Someone can help me?
Had a similar problem, in my case it was enough to add the BullModule to the exports array in order to successfully run the whole project. Like this:
#Module({
imports: [
BullModule.registerQueue({ ... }),
...
],
...
exports: [
BullModule, // <— this is important!
...
]
})
Then in my service I've been able to inject the queue:
#InjectQueue('print') private queue: Queue<PrintJob>
You have to import bull module inside the module you are trying to setup queue. You can also refer https://medium.com/#shikhar01.cse14/bull-queues-in-nestjs-306c51cb0ec2
Make sure you are placing EventService under providers array in EventModule.
#Module({
providers: [EventService],
controllers :[],
imports: [YOUR_MODULES],
exports: [EventService]
})
export class EventModule {}
Try importing BullModule straight in Event Module - I had the same problem and doing it this way make it work.
#Module({
imports: [
BullModule.registerQueueAsync({
name: 'csv',
useFactory: async (config: ConfigService) => ({
redis: config.get('redis'),
}),
inject: [ConfigService],
}),
],
providers: [
CsvService
],
exports: [CsvService],
})
export class CsvModule {}
I know that it's async method, but maybe you should try.
You can do like below
#Module({
imports: [
ConfigModule.forRoot({
load: [configuration],
}),
EventModule,
],
})
export class AppModule {}
#Module({
imports: [
BullModule.registerQueue({
name: 'create_checkin',
redis: {
host: 'localhost',
port: 6379,
},
}),
],
})
export class EventModule {}