nestjs process.env.variable is undefined in my auth.module.ts - nestjs

im trying to test jwt auth in nestjs.
when i called jwtService.sign();
it shows error secretOrPrivateKey must have a value - {}
secret is undefined.
but in AuthController, porcess.env.JWT_SECRET_KEY is work.
i dont know why it is not work.
how can i fix it ?
auth.module.ts
#Module({
imports: [
ConfigModule.forRoot({
isGlobal: true,
load: [AppConfig, MySqlConfig, OracleConfig],
envFilePath: `${process.env.NODE_ENV}` == '' ? '.env.dev' : `.env.${process.env.NODE_ENV}`,
validationSchema: Joi.object({
NODE_ENV: Joi.string()
.valid('dev', 'stg', 'prd'),
}),
}),
AuthModule,
],
controllers: [AppController],
providers: [AppService, Logger],
})
export class AppModule {}
app.module.ts
#Module({
imports: [
PassportModule,
JwtModule.register({
secret: process.env.JWT_SECRET_KEY,
signOptions: { expiresIn: '1d' },
}),
],
controllers: [AuthController],
providers: [AuthService, JwtStrategy, LocalStrategy],
exports: [AuthService],
})
export class AuthModule {}
main.ts
async function bootstrap() {
const app = await NestFactory.create(AppModule, {
bufferLogs: true,
});
app.enableShutdownHooks();
app.useLogger(app.get(MyLogger));
const configService = app.get(ConfigService);
const logger = app.get(MyLogger);
const config = new DocumentBuilder()
.setTitle('nestjs-tst-boilerplate')
.setDescription('The nestjs-tst-boilerplate API description')
.setVersion('0.0.1')
.addTag('tag')
.build();
const document = SwaggerModule.createDocument(app, config);
SwaggerModule.setup('api', app, document);
await app.listen(configService.get<number>('app.port'));
logger.log(`Application running on [${configService.get<string>('app.env')}] enviroment. ${await app.getUrl()}`);
}
bootstrap();

at the time that process.env.JWT_SECRET_KEY is read, the .env might not be parsed yet. Thus, don't rely on process.env. if you're using some module like #nestjs/config. Use the async version of JwtModule.register instead and inject the ConfigService. See: https://github.com/nestjs/jwt/blob/master/README.md#async-options

Related

CRON job executing twice at scheduled time (NestJS)

I want to execute this cron function in my NestJs project :
#Cron('59 23 * * *')
async CashPendingCRON(){
let stores = await this.storeRepository.find();
for (let store of stores){
await this.connection
.createQueryBuilder()
.insert()
.into(CashPending)
.values([
{ cashPending: store.cashPending, store: store }
])
.execute()
}
As you can see the corn job is supposed to execute at 11:59 pm everyday. But it gets executed twice and the entries are logged in the DB two times. When I use intervals like 10 seconds (*/10 * * * * *) it gets called only once.
Please let me know if there is a fix or if I am doing something wrong.
Here is how I added the ScheduleModule in the app.module.ts
#Module({
imports: [
ScheduleModule.forRoot(),
ConfigModule.forRoot({
load: [appConfig, devConfig, stagConfig],
ignoreEnvFile: true,
isGlobal: true,
}),
TypeOrmModule.forRoot(
configService.getTypeOrmConfig(),
),
TypeOrmModule.forFeature([
User,
Vendor,
Store,
Product,
Category,
Brand,
AppVersion
]),
JwtModule.registerAsync({
imports: [ConfigModule],
useFactory: async () => ({
secret: process.env.TOKEN_KEY,
}),
inject: [ConfigService],
}),
UserModule,
UserClusterModule,
StoreModule,
OperationManagerModule,
UserBrandModule,
UserCatalogueModule,
UserPropertyModule,
FileModule,
BrandModule,
CategoryModule,
ProductsModule,
WarehouseModule,
SubCategoryModule,
StoreStocksModule,
WarehouseStockModule,
RtvStocksModule,
VendorModule,
CustomerModule,
W2sModule,
S2sModule,
W2wModule,
BillerModule,
WarehouseManagerModule,
AuthModule,
OrderModule,
GRNModule,
SKUTimelinesModule,
BannerModule,
OrderReturnModule,
UtilModule,
POModule,
AppVersion,
S2wModule,
CashOutModule
],
controllers: [AppController],
providers: [AppService],
})
export class AppModule {}
Please help. Thank you.
I was going through the same issue and the problem was that I was using the imports: [ScheduleModule.forRoot()] in a module that was imported twice (by other two modules). I solved it by creating a new module that is not imported by any other module and adding the ScheduleModule.forRoot() in it.
scheduler.module.ts
#Module({
providers: [SchedulerService],
imports: [ScheduleModule.forRoot()],
})
export class SchedulerModule {}
scheduler.service.ts
import { Injectable } from '#nestjs/common';
import { Cron, CronExpression } from '#nestjs/schedule';
#Injectable()
export class SchedulerService {
#Cron(CronExpression.EVERY_10_SECONDS)
handleExpiration() {
console.log(new Date());
}
}
Console output:
2022-12-21T14:04:00.005Z
2022-12-21T14:04:10.004Z
2022-12-21T14:04:20.009Z
2022-12-21T14:04:30.004Z
2022-12-21T14:04:40.011Z
...

Nest JS's Throttler Guard from REST module is breaking GraphQL module

I have a Nest.js app with a REST module and a GraphQL module. Both are imported into an App.module.ts. I'm using Nest's Throttler Guard to protect the whole application. As it's already known, GraphQL does not work with the normal ThrottlerGuard, so I created a GqlThrottlerGuard and imported it on the GraphQL module, while importing the original ThrottlerGuard on the REST module.
So, my graphQL module looks like this:
#Module({
imports: [
GraphQLModule.forRoot<ApolloDriverConfig>({
driver: ApolloDriver,
autoSchemaFile: true
}),
ThrottlerModule.forRootAsync({
imports: [ConfigModule],
inject: [ConfigService],
useFactory: (config: ConfigService) => ({
ttl: config.get('security.throttle.ttl'),
limit: config.get('security.throttle.limit'),
}),
}),
],
providers: [
{
provide: APP_GUARD,
useClass: GqlThrottlerGuard,
},
],
})
export class GraphModule { }
And the REST module, like this:
#Module({
imports: [
ThrottlerModule.forRootAsync({
imports: [ConfigModule],
inject: [ConfigService],
useFactory: (config: ConfigService) => ({
ttl: config.get('security.throttle.ttl'),
limit: config.get('security.throttle.limit'),
}),
}),
],
controllers: [RestController],
providers: [
{
provide: APP_GUARD,
useClass: ThrottlerGuard,
},
],
})
export class RestModule implements NestModule {}
Finally, both modules are imported to the App Module, which is the module I actually run:
#Module({
imports: [
RestModule,
GraphModule,
],
})
export class AppModule { }
For some reason, the error seen here is still happening to me on the GraphModule, even though the normal ThrottlerGuard is imported only on the RestModule. Should it work like this? How can I solve it?
APP_GUARD is a global binding, it applies to all routes. You should make one coherent guard that returns the proper request response based on the ExecutionContext#getType method which will either return http or graphql
#Injectable()
export class CustomThrottlerGuard extends ThrottlerGuard {
getRequestResponse(context: ExecutionContext) {
const reqType = context.getType<ContextType | 'graphql'>()
if (reqType === 'graphql') {
const gqlCtx = GqlExecutionContext.create(context);
const ctx = gqlCtx.getContext();
return { req: ctx.req, res: ctx.res };
} else if (reqType === 'http') {
return {
req: context.switchToHttp().getRequest(),
res: context.switchToHttp().getResponse()
}
} else {
// handle rpc and ws if you have them, otherwise ignore and make previous `else if` just an `else`
}
}

NestJS -- JWT Dependency is not being loaded

I do not need complete passport, I just need to sign a JWT token.
I tried working with this repository
I tried all possible combinations, but I just cant integrate it in the project. I had followed the course of several different errors. I fix one, and the another pops up. So, I am including minimum part, and the current error that is thrown.
AuthModule:
import { Module } from '#nestjs/common';
import { JwtModule } from '#nestjs/jwt';
import { AuthService } from './auth.service';
import { JwtService } from '#nestjs/jwt';
#Module({
imports: [ JwtModule.register({ secret: 'hard!to-guess_secret' })],
providers: [AuthService],
exports: [AuthService, JwtService]
})
export class AuthModule {}
AuthService:
import { Injectable } from '#nestjs/common';
import { UsersService } from '../users/users.service';
import { JwtService } from '#nestjs/jwt';
#Injectable()
export class AuthService {
constructor(
private readonly jwtService: JwtService,
) {}
async signPayload (user: any) {
const payload = { username: 'HARDCORE', color:'RED' };
return {
whatever: this.jwtService.sign(payload),
};
}
}
AppModule:
#Module({
imports: [
ConfigModule.forRoot(),
JwtModule.registerAsync({
imports: [ConfigModule],
useFactory: async (configService: ConfigService) => ({
secret: 'wefwefwef',
}),
inject: [ConfigService],
}),
TypeOrmModule.forRoot({
type: 'mysql',
...
}),
UsersModule,
SubscriptionsModule,
ProductsModule
],
controllers: [AppController],
providers: [AppService],
})
export class AppModule {
}
SomeController:
export class UsersController {
constructor(private readonly usersService: UsersService,
private readonly authService: AuthService
) {}
...
#ApiResponse({ status: 401, description: 'Unauthorized.' })
#ApiResponse({ status: 404, description: 'User Not Found.' })
#Get('users')
async findOne(#Query() userGetDto: UserGetDto): Promise<User> {
const user = await this.usersService.findByUsername(userGetDto.userName);
if (!user) throw new NotFoundException('User Not Found')
let signedUser = this.authService.signPayload(user);
return user;
And this is the error with this setup that I get:
Nest can't resolve dependencies of the JwtService (?). Please make
sure that the argument JWT_MODULE_OPTIONS at index [0] is available in
the JwtService context.
I spend lot of time on this one, but I just cant make it work.
Based on your error, JwtService is in an imports array somewhere. Providers (classes marked with #Injectable()) never go in the imports array, but rather should be added to the exports array and that module where the exports was added should be put in the consuming module's imports array.
Also, if you are working with a Dynamic Module (any module that uses register or forRoot or an async variant of the two) you should always export the module instead of its services, as the module most likely has important configurations necessary for the service to work.

NestJS Dependency injection fails for imported modules

I inject 3 services in my controller: one is declared as provider inside the controller's module (AnswerModule), the 2 other services are declared in other modules (QuizesModule and QuestionsModule). I import these modules in AnswerModule.
Here the error
Error: Nest can't resolve dependencies of the AnswersController (AnswersService, ?, QuestionsService). Please make sure that the argument QuizesService at index [1] is available in the AnswersModule context.
Potential solutions:
- If QuizesService is a provider, is it part of the current AnswersModule?
- If QuizesService is exported from a separate #Module, is that module imported within AnswersModule?
#Module({
imports: [ /* the Module containing QuizesService */ ]
})
Here are the modules:
QuizesModule
#Module({
imports: [ AuthModule,
MongooseModule.forFeature([{ name: 'Quiz', schema: QuizSchema }]),
],
controllers: [QuizesController],
providers: [QuizesService],
})
export class QuizesModule {}
QuestionsModule:
#Module({
imports: [QuizesModule, MongooseModule.forFeature([{ name: 'Question', schema: QuestionSchema }])],
controllers: [QuestionsController],
providers: [QuestionsService],
exports: [QuizesModule]
})
export class QuestionsModule {}
AnswerModule
#Module({
imports: [QuizesModule, QuestionsModule, MongooseModule.forFeature([{ name: 'Answer', schema: AnswerSchema }])],
controllers: [AnswersController],
providers: [AnswersService,]
})
export class AnswersModule {}
Stacktrace:
Error: Nest can't resolve dependencies of the AnswersController (AnswersService, ?, QuestionsService). Please make sure that the argument QuizesService at index [1] is available in the AnswersModule context.
Potential solutions:
- If QuizesService is a provider, is it part of the current AnswersModule?
- If QuizesService is exported from a separate #Module, is that module imported within AnswersModule?
#Module({
imports: [ /* the Module containing QuizesService */ ]
})
at Injector.lookupComponentInParentModules (/Users/laurent/Projects/perso/nestjs-elearning/node_modules/#nestjs/core/injector/injector.js:191:19)
at processTicksAndRejections (internal/process/task_queues.js:97:5)
at async Injector.resolveComponentInstance (/Users/laurent/Projects/perso/nestjs-elearning/node_modules/#nestjs/core/injector/injector.js:147:33)
at async resolveParam (/Users/laurent/Projects/perso/nestjs-elearning/node_modules/#nestjs/core/injector/injector.js:101:38)
at async Promise.all (index 1)
at async Injector.resolveConstructorParams (/Users/laurent/Projects/perso/nestjs-elearning/node_modules/#nestjs/core/injector/injector.js:116:27)
at async Injector.loadInstance (/Users/laurent/Projects/perso/nestjs-elearning/node_modules/#nestjs/core/injector/injector.js:80:9)
at async Injector.loadController (/Users/laurent/Projects/perso/nestjs-elearning/node_modules/#nestjs/core/injector/injector.js:28:9)
at async Promise.all (index 0)
at async InstanceLoader.createInstancesOfControllers (/Users/laurent/Projects/perso/nestjs-elearning/node_modules/#nestjs/core/injector/instance-loader.js:51:9)
at async /Users/laurent/Projects/perso/nestjs-elearning/node_modules/#nestjs/core/injector/instance-loader.js:29:13
at async Promise.all (index 12)
at async InstanceLoader.createInstances (/Users/laurent/Projects/perso/nestjs-elearning/node_modules/#nestjs/core/injector/instance-loader.js:26:9)
at async InstanceLoader.createInstancesOfDependencies (/Users/laurent/Projects/perso/nestjs-elearning/node_modules/#nestjs/core/injector/instance-loader.js:16:9)
at async /Users/laurent/Projects/perso/nestjs-elearning/node_modules/#nestjs/core/nest-factory.js:81:17
at async Function.asyncRun (/Users/laurent/Projects/perso/nestjs-elearning/node_modules/#nestjs/core/errors/exceptions-zone.js:17:13)
Thanks for your help, I do not understand my settings in modules seem correct
Laurent
exports: [QuizesService], at QuizesModule
The AnswersModule uses this service. So we need to expose it.
Thanks for your answer now it works
Here is the fix... I export QUizesService in QuizesModule, I export AuthModule in QUizesModule, I export QuestionsService in QuestionsModule
#Module({
imports: [ AuthModule,
MongooseModule.forFeature([{ name: 'Quiz', schema: QuizSchema }]),
],
controllers: [QuizesController],
providers: [QuizesService],
//...quizesProviders, ...usersProviders]
exports: [QuizesService, AuthModule]
})
export class QuizesModule {}
QUestionsModule
#Module({
imports: [QuizesModule, MongooseModule.forFeature([{ name: 'Question', schema: QuestionSchema }])],
controllers: [QuestionsController],
providers: [QuestionsService],
exports: [QuestionsService]
})
export class QuestionsModule {}

Mock multiple TypeORM repositories in NestJS

I'm having trouble to mock multiple repositories from different modules in NestJS.
I'm using a UsersRepository from a UsersModule inside another module service (NotesService). The code is working fine, but I can't make the unit tests work.
I have the following error: Error: Nest can't resolve dependencies of the UserRepository (?). Please make sure that the argument Connection at index [0] is available in the TypeOrmModule context.
Minimal reproduction
// [users.module.ts]
#Module({
imports: [TypeOrmModule.forFeature([User])],
controllers: [UsersController],
providers: [UsersService],
exports: [UsersService],
})
export class UsersModule {}
// [users.service.ts]
#Injectable()
export class UsersService {
constructor(#InjectRepository(User) private usersRepository: UsersRepository) {}
...
}
// [notes.module.ts]
#Module({
imports: [
TypeOrmModule.forFeature([Note, User]),
UsersModule,
],
controllers: [NotesController],
providers: [NotesService],
})
export class NotesModule {
}
// [notes.service.ts]
#Injectable()
export class NotesService {
constructor(
#InjectRepository(Note) private notesRepository: NotesRepository,
#InjectRepository(User) private usersRepository: UsersRepository,
) {}
...
}
Here is my unit test configuration:
// [notes.service.spec.ts]
beforeEach(async () => {
const module = await Test.createTestingModule({
imports: [UsersModule],
providers: [
NotesService,
{ provide: getRepositoryToken(Note), useFactory: repositoryMockFactory },
{ provide: getRepositoryToken(User), useFactory: repositoryMockFactory },
],
}).compile();
notesService = module.get<NotesService>(NotesService);
notesRepositoryMock = module.get(getRepositoryToken(Note));
});
The problem is I can't make a proper mock of the UsersRepository that comes from another module.
I tried importing TypeOrmModule directly inside the test, and everything I could but I can't make it work.
You don't need to import the UsersModule if you are directly providing the NotesService and the mocks that it will depend on. The reason for the error is that Nest is trying to resolve TypeormModule.forFeature([User]) from the UsersModule. Simply remove the import in the test and you should be golden.

Resources