@ValidatorConstraint({ async: true })
@Injectable()
export class IsValidWorkingHourConstraint implements ValidatorConstraintInterface {
private readonly WORKING_HOUR_START: number;
private readonly WORKING_HOUR_END: number;
constructor(protected readonly helperDateService: HelperDateService, private readonly configService: ConfigService) {
this.WORKING_HOUR_START = this.configService.get<number>('workStartHour');
// ^^^^^this thrown the error
this.WORKING_HOUR_END = this.configService.get<number>('workEndHour');
}
validate(value: string | number | Date) {
const date = new Date(value);
const day = date.getDay(); // 0 (Sunday) to 6 (Saturday)
const hours = date.getHours(); // 0 to 23
if (!this.helperDateService.isWorkingDay(day)) {
return false;
}
if (hours < this.WORKING_HOUR_START || hours >= this.WORKING_HOUR_END) {
return false;
}
return true;
}
}
As you can see, ConfigService
is Injected, but the error says it is undefined.
@Module({
controllers: [],
providers: [
{
provide: APP_INTERCEPTOR,
useClass: RequestTimeoutInterceptor,
},
{
provide: APP_PIPE,
useFactory: () =>
new ValidationPipe({
transform: true,
skipNullProperties: false,
skipUndefinedProperties: false,
skipMissingProperties: false,
forbidUnknownValues: false,
errorHttpStatusCode: HttpStatus.UNPROCESSABLE_ENTITY,
exceptionFactory: async (errors: ValidationError[]) =>
new UnprocessableEntityException({
statusCode: ENUM_REQUEST_STATUS_CODE_ERROR.REQUEST_VALIDATION_ERROR,
message: 'request.validation',
errors,
}),
}),
},
{
provide: APP_GUARD,
useClass: ThrottlerGuard,
},
IsValidWorkingHourConstraint,
],
imports: [
RequestMiddlewareModule,
ThrottlerModule.forRootAsync({
imports: [ConfigModule],
inject: [ConfigService],
useFactory: (config: ConfigService) => ({
ttl: config.get('request.throttle.ttl'),
limit: config.get('request.throttle.limit'),
}),
}),
],
})
export class RequestModule {}
TypeError: Cannot read properties of undefined (reading 'get')
at new IsValidWorkingHourConstraint (A:\DEV\HR\deadline-calculator\src\common\request\validations\request.is-valid-working-hour.validation.ts:17:50)
at Object.get (A:\DEV\HR\deadline-calculator\node_modules\src\container.ts:25:45)
at getFromContainer (A:\DEV\HR\deadline-calculator\node_modules\src\container.ts:58:27)
at ConstraintMetadata.get instance [as instance] (A:\DEV\HR\deadline-calculator\node_modules\src\metadata\ConstraintMetadata.ts:45:28)
at A:\DEV\HR\deadline-calculator\node_modules\src\validation\ValidationExecutor.ts:271:59
at Array.forEach (<anonymous>)
at A:\DEV\HR\deadline-calculator\node_modules\src\validation\ValidationExecutor.ts:253:82
at Array.forEach (<anonymous>)
at ValidationExecutor.customValidations (A:\DEV\HR\deadline-calculator\node_modules\src\validation\ValidationExecutor.ts:252:15)
at ValidationExecutor.performValidations (A:\DEV\HR\deadline-calculator\node_modules\src\validation\ValidationExecutor.ts:212:10),
I tried to add ConfigModule and ConfigService to RequestModule, but neither helped.
I also tried to inject the service and assign it as shown below:
@Inject(ConfigService)
private readonly configService: ConfigService
constructor (configService: ConfigService) {
this.service = service
}
EDIT: The HelperDateService is also not working in this service.
You cannot auto-inject dependencies into @ValidatorConstraint
using NestJS.
You can instead do a workaround in your main.ts
file.
import { useContainer } from 'class-validator';
import { ApplicationModule } from './app.module';
async function bootstrap() {
const app = await NestFactory.create(ApplicationModule);
useContainer(app.select(ApplicationModule), { fallbackOnErrors: true });
await app.listen(3000);
}
bootstrap()
By using the above workaround, class-validator
will be using the module resolution from NestJS, and the dependency injection in @ValidatorConstraint
should work now.