I have some projects with nestjs, I've always used the class validator, but recently it doesn't seem to be working. It simply doesn't call the DTO to validate.
controller
#Post()
async create(#Body() body: UserDTO) {
return body;
}
My DTO
import { IsNotEmpty, IsString } from 'class-validator';
export class UserDTO {
#IsNotEmpty()
#IsString()
name: string;
}
main
app.useGlobalPipes(
new ValidationPipe({
whitelist: true,
forbidNonWhitelisted: true,
transform: true,
}),
);
versions class validator and class transformer
"class-transformer": "^0.5.1",
"class-validator": "^0.13.2",
Solved, the solution was to instantiate the validation pipe inside the input module
#Module({
imports: [ConfigModule.forRoot(), UserModule, AuthModule],
controllers: [],
providers: [
{
provide: APP_PIPE,
useValue: new ValidationPipe({
whitelist: true,
forbidNonWhitelisted: true,
transform: true,
}),
},
],
})
export class AppModule {}
Related
The nestjs class-validator does not work.
For example, if I send a post request with a number for LoginId, I get a normal response.
import { IsNumber, IsString } from 'class-validator';
export class LoginUserDto {
#IsString()
loginId: string;
#IsString()
password: string;
}
class-validator needs to work with Pipe.
You can refer to the following code to inject APP_PIPE or see the nestjs/pipe doc.
import { Module, ValidationPipe } from '#nestjs/common';
import { APP_PIPE } from '#nestjs/core';
import { AppController } from './app.controller';
import { AppService } from './app.service';
#Module({
imports: [],
controllers: [AppController],
providers: [
AppService,
{
provide: APP_PIPE,
useValue: new ValidationPipe({
whitelist: true,
}),
},
],
})
export class AppModule {}
Class Validator should work I am Using it for a long time.
I think in your case it treats LoginId(number, your input) as a string
Try Class Transformer
import { IsNumber, IsString, IsNotEmpty() } from 'class-validator';
import { Type } from 'class-transformer';
export class LoginUserDto {
#IsNotEmpty()
#IsString()
#Type(()=>String)
loginId: string;
#IsString()
#IsNotEmpty()
password: string;
}
In NestJS Documentation, it says that when I make custom repository, I don't need to use #InjectRepository() decorator docs
But in my code, I cannot inject my custom repository like that
these are my codes
app.module.ts
#Module({
imports: [
CacheModule.register(),
ConfigModule.forRoot({
isGlobal: true
}),
TypeOrmModule.forRootAsync({
useFactory: () => ({
type: 'postgres',
host: process.env.DB_HOST,
port: +process.env.DB_PORT,
username: process.env.DB_NAME,
password: process.env.DB_PASSWORD,
database: process.env.DB_DATABASE,
entities: [`${__dirname}/**/entities/*.entity{.ts,.js}`],
synchronize: true,
logging: true
})
}),
GraphQLModule.forRoot<ApolloDriverConfig>({
driver: ApolloDriver,
cors: {
origin: 'http://localhost:3000',
credentials: true
},
autoSchemaFile: 'schema.gql'
}),
AuthModule,
UserModule,
]
})
export class AppModule {}
user.repository.ts
#EntityRepository(User)
export class UserRepository extends Repository<User> {}
user.module.ts
#Module({
imports: [TypeOrmModule.forFeature([UserRepository]), CacheModule.register()],
providers: [
UserResolver,
UserService,
],
exports: [UserService, TypeOrmModule]
})
export class UserModule {}
user.service.ts
#Injectable()
export class UserService {
constructor(
private readonly userRepository: UserRepository,
#Inject(CACHE_MANAGER) private cacheManager: Cache
) {}
}
error message
ERROR [ExceptionHandler] Nest can't resolve dependencies of the UserService (?, CACHE_MANAGER). Please make sure that the argument UserRepository at index [0] is available in the UserModule context.
Potential solutions:
- If UserRepository is a provider, is it part of the current UserModule?
- If UserRepository is exported from a separate #Module, is that module imported within
UserModule?
#Module({
imports: [ /* the Module containing UserRepository */ ]
})
I don't want to use #InjectRepository(UserRepositry) decorator.
How can I do that?
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
#Module({
imports: [],
providers: [SupertokensService, AuthService],
exports: [],
controllers: [AuthController],
})
export class AuthModule implements NestModule {
configure(consumer: MiddlewareConsumer) {
consumer.apply(AuthMiddleware).forRoutes('*');
}
static forRoot({
connectionURI,
apiKey,
appInfo,
}: AuthModuleConfig): DynamicModule {
return {
providers: [
{
useValue: {
appInfo,
connectionURI,
apiKey,
},
provide: ConfigInjectionToken,
},
],
exports: [],
imports: [],
module: AuthModule,
};
}
}
The problem with this implementaion I can't use env variables, so I need useFactory to pass ConfigService. Can somebody do that, and give some explanation.
I figure out how to make this work, unfortunately it only works with nest.js version 9 (current latest version). First you need to create a new file. For example auth.module-definition.ts. Now in this file we need to create ConfigurableModuleBuilder.
import { ConfigurableModuleBuilder } from '#nestjs/common';
import { AuthModuleConfig } from './config.interface';
export const { ConfigurableModuleClass, MODULE_OPTIONS_TOKEN } =
new ConfigurableModuleBuilder<AuthModuleConfig>()
.setClassMethodName('forRoot')
.build();
we need to set setClassMethodName('forRoot'), when we set forRoot it will create two methods, forRoot and forRootAsync. The next step is to extend our created ConfigurableModuleClass. it should look something like this
import { MiddlewareConsumer, Module } from '#nestjs/common';
import { AuthMiddleware } from './auth.middleware';
import { SupertokensService } from './supertokens/supertokens.service';
import { AuthController } from './auth.controller';
import { AuthService } from './auth.service';
import { ConfigurableModuleClass } from './auth.module-definition';;
#Module({
imports: [],
providers: [SupertokensService, AuthService],
controllers: [AuthController],
exports: [AuthService],
})
export class AuthModule extends ConfigurableModuleClass {
configure(consumer: MiddlewareConsumer) {
consumer.apply(AuthMiddleware).forRoutes('*');
}
}
And that's actually it, so from now on we have forRootAsync and we get reigister it in app.module.ts
import { MiddlewareConsumer, Module, NestModule } from '#nestjs/common';
import { AuthModule } from './auth/auth.module';
import { ConfigModule, ConfigType } from '#nestjs/config';
import authConfig from './auth/auth.config';
#Module({
imports: [
AuthModule.forRootAsync({
inject: [authConfig.KEY],
imports: [ConfigModule.forFeature(authConfig)],
useFactory: (config: ConfigType<typeof authConfig>) => {
return {
connectionURI: config.CONNECTION_URI,
appInfo: {
appName: config.appInfo.APP_NAME,
apiDomain: config.appInfo.API_DOMAIN,
websiteDomain: config.appInfo.WEBSITE_DOMAIN,
apiBasePath: config.appInfo.API_BASE_PATH,
websiteBasePath: config.appInfo.WEBSITE_BASE_PATH,
},
};
},
})
],
controllers: [],
providers: [
],
})
export class AppModule implements NestModule {
}
here I am using Nest.js Config, but you don't need to, so use it how you want.
I know that my english is not the best, so if you still do not understand you can check these sources https://docs.nestjs.com/fundamentals/dynamic-modules#configurable-module-builder
https://trilon.io/blog/nestjs-9-is-now-available#Configurable-module-builder
After configured cache globally like the docs, the CacheInterceptor throws an error if i use it outside the app.module.
app.module.ts
const cacheConfig = {
store: redisStore,
host: 'localhost',
port: 6379
}
#Module({
imports: [
CacheModule.register(cacheConfig),
CustomerModule,
],
providers: [
{
provide: APP_INTERCEPTOR,
useClass: CacheInterceptor
}
]
})
export class AppModule {}
customer.module.ts
#Module({
imports: [TypeOrmModule.forFeature([CustomerRepository]), TypeOrmModule.forFeature([User])],
controllers: [CustomerController]
})
export class CustomerModule {}
customer.controller.ts
#Controller('customer')
export class CustomerController {
constructor(
#InjectRepository(CustomerRepository) private customerRepository: CustomerRepository,
#InjectRepository(User) private userRepository: Repository<User>
) {}
#Get()
#UseInterceptors(CacheInterceptor)
async get(): Promise<any> {
const user = await this.userRepository.findOne({ where: { id: 1 }, relations: ['customer'] })
console.log(user.customer.name)
const customer = await this.customerRepository.findOne({ where: { id: 1 }, select: ['id', 'name'] })
return { customer: customer.name, email: user.email }
}
}
I would like using the CacheInterceptor along any modules without import the CacheModule each one.
Nest can't resolve dependencies of the APP_INTERCEPTOR (UUID: 6aa42c77-1bac-4098-b217-1b01eb268240) (?, Reflector). Please make sure that the argument at index [0] is available in the CustomerModule context.
If you have { provide: APP_INTERCEPTOR, useClass: CacheInterceptor } you don't need to add in the #UseInterceptors() decorator in your controller. You should have the CahceInterceptor working by default with the rest of the set up