Nest can't resolve dependencies - node.js

I ran into a problem with NestJS dependencies, I just started learning Nest and still don't quite understand how to build the structure correctly.
Nest can't resolve dependencies of the ChatGateway (?). Please make sure that the argument ChatAuth at index [0] is available in the ChatGateway context.
My error in terminal
chat.module.ts
`
import { Module } from '#nestjs/common';
import { ChatAuth } from './chat.middlewares';
import { ChatGateway } from './chat.gateway';
import { AuthHelper } from '../auth/auth.helper';
import { JwtStrategy } from '../auth/auth.strategy';
#Module({
imports: [ChatGateway, ChatAuth],
controllers: [],
providers: [AuthHelper, JwtStrategy],
})
export class ChatModule {}
`
chat.gateway.ts
`
import {
SubscribeMessage,
WebSocketGateway,
OnGatewayInit,
WebSocketServer,
OnGatewayConnection,
OnGatewayDisconnect,
MessageBody,
} from '#nestjs/websockets';
import { Logger } from '#nestjs/common';
import { Socket, Server } from 'socket.io';
import { ChatAuth } from './chat.middlewares';
#WebSocketGateway(7000)
export class ChatGateway
implements OnGatewayInit, OnGatewayConnection, OnGatewayDisconnect
{
#WebSocketServer() server: Server;
private chatAuthHelper: ChatAuth;
private logger: Logger = new Logger('ChatGateway');
constructor(chatAuthHelper: ChatAuth) {
this.chatAuthHelper = chatAuthHelper;
}
#SubscribeMessage('msgToServer')
handleMessage(client: Socket, payload: string): void {
console.log(payload);
this.server.emit('msgToClient', payload);
}
#SubscribeMessage('events')
handleEvent(#MessageBody() data: string): void {
const parsed = JSON.parse(JSON.stringify(data));
parsed.msg = parsed.msg + ' 3';
this.server.emit('onMessage', {
msg: 'New message',
content: parsed.msg,
});
}
afterInit(server: Server) {
this.logger.log('Init');
}
handleDisconnect(client: Socket) {
this.logger.log(`Client disconnected: ${client.id}`);
}
handleConnection(client: Socket, ...args: any[]) {
if (client.handshake.headers.authorization) {
const guard = this.chatAuthHelper.use(
client.handshake.headers.authorization,
);
}
this.logger.log(`Client connected: ${client.id}`);
}
}
`
chat.middlewares.ts
`
import { Injectable, NestMiddleware } from '#nestjs/common';
import { AuthHelper } from '../auth/auth.helper';
#Injectable()
export class ChatAuth implements NestMiddleware {
private helper: AuthHelper;
constructor(helper: AuthHelper) {
this.helper = helper;
}
public async use(token): Promise<object> {
const currentToken = token.split(' ')[1];
const user = await this.helper.validate(currentToken);
console.log(JSON.stringify(user));
return user;
}
}
`
app.module.ts
`
import { Module } from '#nestjs/common';
import * as path from 'path';
import { ConfigModule } from '#nestjs/config';
import { TypeOrmModule } from '#nestjs/typeorm';
import { AppController } from './app.controller';
import { AppService } from './app.service';
import { getEnvPath } from './common/helper/env.helper';
import { TypeOrmConfigService } from './shared/typeorm/typeorm.service';
import { ApiModule } from './api/api.module';
import { ChatModule } from './api/chat/chat.module';
const getPathConfig: string = path.join(__dirname, '..', 'env');
const envFilePath: string = getEnvPath(getPathConfig);
#Module({
imports: [
ConfigModule.forRoot({ envFilePath, isGlobal: true }),
TypeOrmModule.forRootAsync({ useClass: TypeOrmConfigService }),
ApiModule,
ChatModule,
],
controllers: [AppController],
providers: [AppService],
})
export class AppModule {}
`
Swapped ChatAuth / ChatModule imports

come on, read the docs :D
ChatAuth is not a module, then there's no reason it to be listed in the imports array.
the page https://docs.nestjs.com/websockets/gateways shows that the gateway should be in the providers array. Again, ChatGateway is not a module, then why did you put that into imports array? the docs are pretty clear on what is the role of each option of #Module({}).

Related

nestjs jwt implementation is stuck - Nest can't resolve dependencies of the JWT_MODULE_OPTIONS (?)

I'm trying to implement JWT with NestJs. In my user.module.ts, I have added following configuration:
import { Module } from '#nestjs/common';
import { ConfigService } from '#nestjs/config';
import { UserService } from './user.service';
import { UserResolver } from './user.resolver';
import { User } from './entities/user.entity';
import { TypeOrmModule } from '#nestjs/typeorm';
import { AuthHelper } from './auth/auth.helper';
import { JwtStrategy } from './auth/auth.strategy';
import { PassportModule } from '#nestjs/passport';
import { JwtModule } from '#nestjs/jwt';
#Module({
imports: [
// PassportModule.register({ defaultStrategy: 'jwt', property: 'user' }),
// JwtModule.registerAsync({
// inject: [ConfigService],
// useFactory: (config: ConfigService) => ({
// secret: 'secret',
// signOptions: { expiresIn: 36000000 },
// }),
// }),
TypeOrmModule.forFeature([User]),
],
providers: [UserResolver, UserService], // AuthHelper, JwtStrategy],
})
export class UserModule {}
Whenever I uncomment these lines, I get some issues.
Here are some relevant files:
auth.strategy.ts
import { Injectable, Inject } from '#nestjs/common';
import { ConfigService } from '#nestjs/config';
import { PassportStrategy } from '#nestjs/passport';
import { ExtractJwt, Strategy } from 'passport-jwt';
import { User } from '../entities/user.entity';
import { AuthHelper } from './auth.helper';
#Injectable()
export class JwtStrategy extends PassportStrategy(Strategy) {
#Inject(AuthHelper)
private readonly helper: AuthHelper;
constructor(#Inject(ConfigService) config: ConfigService) {
super({
jwtFromRequest: ExtractJwt.fromAuthHeaderAsBearerToken(),
secretOrKey: 'KhubSecret',
ignoreExpiration: true,
});
}
private validate(payload: string): Promise<User | never> {
return this.helper.validateUser(payload);
}
}
auth.guard.ts
import { Injectable, ExecutionContext } from '#nestjs/common';
import { AuthGuard, IAuthGuard } from '#nestjs/passport';
import { User } from '../entities/user.entity';
#Injectable()
export class JwtAuthGuard extends AuthGuard('jwt') implements IAuthGuard {
public handleRequest(err: unknown, user: User): any {
return user;
}
public async canActivate(context: ExecutionContext): Promise<boolean> {
await super.canActivate(context);
const { user } = context.switchToHttp().getRequest();
return user ? true : false;
}
}
auth.helper.ts:
import {
Injectable,
HttpException,
HttpStatus,
UnauthorizedException,
} from '#nestjs/common';
import { JwtService } from '#nestjs/jwt';
import { InjectRepository } from '#nestjs/typeorm';
import { Repository } from 'typeorm';
import * as bcrypt from 'bcryptjs';
import { User } from '../entities/user.entity';
#Injectable()
export class AuthHelper {
#InjectRepository(User)
private readonly repository: Repository<User>;
private readonly jwt: JwtService;
constructor(jwt: JwtService) {
this.jwt = jwt;
}
public async decode(token: string): Promise<unknown> {
return this.jwt.decode(token, null);
}
public async validateUser(decoded: any): Promise<User> {
return this.repository.findOne(decoded.id);
}
public generateToken(user: User): string {
return this.jwt.sign({
id: user.userId,
username: user.username,
});
}
public isPasswordValid(password: string, userPassword: string): boolean {
return bcrypt.compareSync(password, userPassword);
}
public encodePassword(password: string): string {
const salt: string = bcrypt.genSaltSync(10);
return bcrypt.hashSync(password, salt);
}
private async validate(token: string): Promise<boolean | never> {
const decoded: unknown = this.jwt.verify(token);
if (!decoded) {
throw new HttpException('Forbidden', HttpStatus.FORBIDDEN);
}
const user: User = await this.validateUser(decoded);
if (!user) {
throw new UnauthorizedException();
}
return true;
}
}
I get some error like this:
[Nest] 18360 - 05/10/2022, 18:14:42 ERROR [ExceptionHandler] Nest can't resolve dependencies of the JWT_MODULE_OPTIONS (?). Please make sure that the argument ConfigService at index [0] is available in the JwtModule context.
Potential solutions:
- If ConfigService is a provider, is it part of the current JwtModule?
- If ConfigService is exported from a separate #Module, is that module imported within JwtModule?
#Module({
imports: [ /* the Module containing ConfigService */ ]
})
Error: Nest can't resolve dependencies of the JWT_MODULE_OPTIONS (?). Please make sure that the argument ConfigService at index [0] is available in the JwtModule context.
Potential solutions:
- If ConfigService is a provider, is it part of the current JwtModule?
- If ConfigService is exported from a separate #Module, is that module imported within JwtModule?
#Module({
imports: [ /* the Module containing ConfigService */ ]
})
I have already tested and implemented these solutions:
NestJS can't resolve dependencies of the JWT_MODULE_OPTIONS
Here is the solution. I hope it would help.
In your auth strategy add this:
constructor() {
super({
jwtFromRequest: ExtractJwt.fromAuthHeaderAsBearerToken(),
secretOrKey: 'KhubSecret',
ignoreExpiration: true,
});
}
instead of:
constructor(#Inject(ConfigService) config: ConfigService) {
super({
jwtFromRequest: ExtractJwt.fromAuthHeaderAsBearerToken(),
secretOrKey: 'KhubSecret',
ignoreExpiration: true,
});
}
In Short, Remove
#Inject(ConfigService) config: ConfigService
from your constructor
From the immediate error you've provided, I'll assume that your ConfigModule is not global. This means that you'll need to import the ConfigModule in the JwtModule.registerAsync() call (in the imports array). Another option would be to make your ConfigModule global (#nestjs/config has an option for this) so that you already have access to ConfigService.

dataSource.createEntityManager is not a function typeorm nest.js

Used "#nestjs/typeorm": "^9.0.1", "typeorm": "^0.3.9"
when using the withRepository method, an exception is thrown
ERROR [ExceptionsHandler] dataSource.createEntityManager is not a function
TypeError: dataSource.createEntityManager is not a function
import { Injectable } from "#nestjs/common";
import { DataSource } from "typeorm";
#Injectable()
export class BarService {
constructor(
private readonly barRepository: BarRepository,
private readonly dataSource: DataSource
) {}
async foo() {
await this.dataSource.manager.transaction((manager) => {
const barRepository = manager.withRepository(this.barRepository);
return;
});
}
}
import { Injectable } from '#nestjs/common';
import { DataSource, Repository } from 'typeorm';
import { BarEntity } from '../entities/bar.entity';
#Injectable()
export class BarRepository extends Repository<BarEntity> {
constructor(dataSource: DataSource) {
super(BarEntity, dataSource.createEntityManager());
}
}
import { Module } from '#nestjs/common';
import { TypeOrmModule } from '#nestjs/typeorm';
import { BarEntity } from './entities/bar.entity';
import { BarService } from './services/bar.service';
import { BarRepository } from './repositories/bar.repository';
#Module({
imports: [TypeOrmModule.forFeature([BarEntity])],
providers: [
BarService,
BarRepository
],
exports: [BarService],
})
export class BarModule {}
error at debbuger

NestJs can't resolve dependencies of the HeicService

I am getting the following error when trying to spin up nestjs
[Nest] 47548 - 04/23/2022, 10:41:12 AM ERROR [ExceptionHandler] Nest can't resolve dependencies of the HeicService (?, +). Please make sure that the argument dependency at index [0] is available in the HeicModule context.
Potential solutions:
- If dependency is a provider, is it part of the current HeicModule?
- If dependency is exported from a separate #Module, is that module imported within HeicModule?
#Module({
imports: [ /* the Module containing dependency */ ]
})
But as from my understanding I am doing everything right regards import/export of Modules, no circular dependency and so on. Here are my modules:
App
import { Module } from '#nestjs/common';
import { EurekaModule } from './eureka/eureka.module';
import { HeicModule } from './heic/heic.module';
#Module({
imports: [HeicModule, EurekaModule],
})
export class AppModule {}
Config
import { Module } from '#nestjs/common';
import { ConfigService } from './config.service';
#Module({
providers: [ConfigService],
exports: [ConfigService],
})
export class ConfigModule {}
ConfigService
import { Injectable } from '#nestjs/common';
import { Config } from './config.interface';
#Injectable()
export class ConfigService {
private readonly map: Config;
Redis
import { CacheModule, Module } from '#nestjs/common';
import { ClientsModule, Transport } from '#nestjs/microservices';
import { ConfigModule } from '../config/config.module';
import { ConfigService } from '../config/config.service';
import { RedisCacheService } from './redis-cache.service';
import * as redisStore from 'cache-manager-redis-store';
import { RedisPublishService } from './redis-publish.service';
#Module({
imports: [
CacheModule.register({
imports: [ConfigModule],
inject: [ConfigService],
useFactory: async (configService: ConfigService) => ({
store: redisStore,
host: configService.get('host'),
port: configService.get('port'),
keyPrefix: configService.get('keyPrefix'),
userName: configService.get('username'),
password: configService.get('password'),
ttl: configService.get('cacheTTL'),
}),
}),
ClientsModule.register([
{
name: 'PUBLISH_SERVICE',
transport: Transport.REDIS,
options: {
url: 'redis://localhost:6379',
},
},
]),
],
providers: [RedisCacheService, RedisPublishService],
exports: [RedisCacheService, RedisPublishService],
})
export class RedisModule {}
Redis Pub/Sub Service
import { Inject, Injectable } from '#nestjs/common';
import { ClientProxy } from '#nestjs/microservices';
import { ImageMessage } from './ImageMessage';
#Injectable()
export class RedisPublishService {
private readonly CHANNEL: string = 'heic-image-result';
constructor(#Inject('PUBLISH_SERVICE') private client: ClientProxy) {}
async publishMessage(imageMessage: ImageMessage) {
this.client.emit({ cmd: this.CHANNEL }, imageMessage);
}
}
Redis Cache Service
import { CACHE_MANAGER, Inject, Injectable } from '#nestjs/common';
import { Cache } from 'cache-manager';
import { ImageMessage } from './ImageMessage';
#Injectable()
export class RedisCacheService {
constructor(#Inject(CACHE_MANAGER) private readonly cache: Cache) {}
async get(key): Promise<ImageMessage> {
return this.cache.get(key);
}
async set(key, value) {
await this.cache.set(key, value, 120);
}
}
Heic
import { Module } from '#nestjs/common';
import { RedisModule } from '../redis/redis.module';
import { HeicService } from './heic.service';
import { MessageListenerController } from './message-listener.controller';
#Module({
imports: [RedisModule],
controllers: [MessageListenerController],
providers: [HeicService],
exports: [HeicService],
})
export class HeicModule {}
Service
import { Inject, Injectable } from '#nestjs/common';
import { ImageMessage } from '../redis/ImageMessage';
import { RedisCacheService } from '../redis/redis-cache.service';
import { RedisPublishService } from '../redis/redis-publish.service';
import { OutputFormatEnum } from './output-format.enum';
// eslint-disable-next-line #typescript-eslint/no-var-requires
const convert = require('heic-convert');
#Injectable()
export class HeicService {
constructor(
#Inject() private readonly redisPublishService: RedisPublishService,
#Inject() private readonly redisCache: RedisCacheService,
) {}
Anyone an idea what I am doing wrong?
You're using #Inject() in your constructors with no injection token. You should be passing the injection token you are wanting to inject here. The HeicService's constructor would then look something like this:
#Injectable()
export class HeicService {
constructor(
#Inject(RedisPublishService) private readonly redisPublishService: RedisPublishService,
#Inject(RedisCacheService) private readonly redisCache: RedisCacheService,
) {}
}
The other option, as you're already using classes for the RedisCacheService and RedisPublishService is to just remove the #Inject() decorators all togehter for the HeicService

NestJS with Typeorm can't resolve dependencies

Problem
NestJS with Typeorm dependancy error.
Description
When I insert #InjectRepository into my Session Repository class (session.repository.ts), the can't dependency errors occur. However, if I remove the #InjectRepository the error disappear and the application works fine.
Error
File: session.repository.ts
import { Injectable } from '#nestjs/common';
import { InjectRepository } from '#nestjs/typeorm';
import { Repository } from 'typeorm';
import { Session } from './session.entity';
#Injectable()
export class SessionRepository {
constructor(
// When I try to inject repository the error occur.
// When I remove the inject repository, no error occur.
#InjectRepository(Session)
private readonly session: Repository<Session>,
) {}
async test() {
return await this.session.find();
}
}
File: session.service.ts
import { Injectable } from '#nestjs/common';
import { ISessionConfig } from 'src/common/config/config.interface';
import { ConfigService } from 'src/common/config/config.service';
import { createHashedToken, getExpiresTime } from '../auth.helper';
import { SessionRepository } from './session.repository';
#Injectable()
export class SessionService {
private bytes: number;
private ttl: number;
constructor(
private readonly configService: ConfigService,
private readonly sessionRepository: SessionRepository,
) {
const sessionConfig = this.configService.get<ISessionConfig>('session');
this.bytes = sessionConfig.bytes;
this.ttl = sessionConfig.ttl;
}
getConfig(): ISessionConfig {
return { bytes: this.bytes, ttl: this.ttl };
}
async generateRefreshToken() {
const refreshToken = await createHashedToken(this.bytes);
const expires = getExpiresTime(this.ttl).toString();
return { refreshToken, expires };
}
}
File: session.module.ts
import { Module } from '#nestjs/common';
import { TypeOrmModule } from '#nestjs/typeorm';
import { Session } from './session.entity';
import { SessionRepository } from './session.repository';
import { SessionService } from './session.service';
#Module({
imports: [TypeOrmModule.forFeature([Session])],
providers: [SessionService, SessionRepository],
exports: [SessionService, SessionRepository],
})
export class SessionModule {}
File: auth.module.ts
import { Module } from '#nestjs/common';
import { AuthenticationModule } from './authentication/authentication.module';
import { JwtModule } from './jwt/jwt.module';
import { SessionModule } from './session/session.module';
#Module({
imports: [AuthenticationModule, JwtModule, SessionModule],
})
export class AuthModule {}
File: database.module.ts
import { Module } from '#nestjs/common';
import { TypeOrmModule, TypeOrmModuleOptions } from '#nestjs/typeorm';
import { IDatabaseConfig } from '../config/config.interface';
import { ConfigService } from '../config/config.service';
#Module({
imports: [
TypeOrmModule.forRootAsync({
inject: [ConfigService],
useFactory: (configService: ConfigService): TypeOrmModuleOptions => {
const dbConfig = configService.get<IDatabaseConfig>('database');
return {
type: 'mysql',
host: dbConfig.host,
port: dbConfig.port,
username: dbConfig.username,
password: dbConfig.password,
database: dbConfig.database,
entities: ['dist/**/*.entity{.ts,.js}'],
autoLoadEntities: true,
synchronize: true,
};
},
}),
],
})
export class DatabaseModule {}
File: app.module.ts
import { MiddlewareConsumer, Module, NestModule } from '#nestjs/common';
import { ConfigModule } from './common/config/config.module';
import { DatabaseModule } from './common/database/database.module';
import { HttpLoggerMiddleware } from './common/middlewares/http-logger.middleware';
import { AuthModule } from './modules/auth/auth.module';
import { PostsModule } from './modules/posts/posts.module';
import { UsersModule } from './modules/users/users.module';
#Module({
imports: [AuthModule, ConfigModule, DatabaseModule, PostsModule, UsersModule],
})
export class AppModule implements NestModule {
configure(consumer: MiddlewareConsumer) {
consumer.apply(HttpLoggerMiddleware).forRoutes('*');
}
}
I tried to solve the issue but, at the end, I am not able to solve it.
Please help me find the issue. Thank you.
Updated
I found out the problem, it is the naming issue. I changed the class name from SessionRepository -> SessionsRepository.

NestJS: inject custom service into MongooseModule

Trying to inject my own GoogleService to use it in Facility schema's pre-save hook. But as soon as i add imports: [GoogleModule], pre-save hook is not invoked without any errors. Same type of injection works with default ConfigModule fine.
google.module.ts:
import { Module } from '#nestjs/common';
import { ConfigModule } from '#nestjs/config';
import { GoogleService } from './google.service';
#Module({
imports: [ConfigModule],
providers: [GoogleService],
exports: [GoogleService]
})
export class GoogleModule { }
facilities.module.ts:
import { MongooseModule } from '#nestjs/mongoose';
import { Module } from '#nestjs/common';
import { ConfigModule } from '#nestjs/config';
import * as zip2tz from 'zipcode-to-timezone';
import { FacilitiesService } from './facilities.service';
import { UsersModule } from '../users/users.module';
import { ShiftTemplatesModule } from '../shift-templates/shift-templates.module';
import { FacilitiesController } from './facilities.controller';
import { Facility, FacilitySchema, FacilityDocument } from './schemas/facility.schema';
import { MailerModule } from '../thirdparty/mailer/mailer.module';
import { ServicedStatesModule } from './../serviced-states/serviced-states.module';
import { GoogleModule } from '../thirdparty/google/google.module';
import { GoogleService } from '../thirdparty/google/google.service';
#Module({
imports: [
ShiftTemplatesModule,
MongooseModule.forFeatureAsync([{
imports: [GoogleModule],
inject: [GoogleService],
name: Facility.name,
useFactory: async (googleService: GoogleService) => {
const schema = FacilitySchema;
schema.pre<FacilityDocument>('save', async function (next) {
console.log('****************************8') //this isn't invoked, however it is with no imports
console.log('PRESAVE')
if (!this.timezone || this.isModified('address')) {
this.timezone = zip2tz.lookup(this.address.zip) || 'America/New_York';
}
if (!this.address.lat || !this.address.long || this.isModified('address')) {
this.address = await googleService.attachCoordinatesToAddress(this.address);
}
next();
});
return schema;
}
}]),
UsersModule,
MailerModule,
ConfigModule,
ServicedStatesModule,
GoogleModule
],
controllers: [FacilitiesController],
providers: [FacilitiesService],
exports: [FacilitiesService]
})
export class FacilitiesModule { }

Resources