I'm trying to use class validator in order to validate incoming data. The data consists of an array of object. Each object should be validated.
The problem that I am facing is that I keep on getting errors when everything is being input correctly. It seems that the parent class is being checked with it's children's properties and so whitelistValidation error is being thrown for each property of the child.
This is the error that is being generated:
[
{
"target":{
"drainPoints":[
{
"drainPointType":"roundsurface",
"flowType":"normal",
"flowCoefficient":0.5,
"point":{
"x":0,
"y":0
}
}
]
},
"value":[
{
"drainPointType":"roundsurface",
"flowType":"normal",
"flowCoefficient":0.5,
"point":{
"x":0,
"y":0
}
}
],
"property":"drainPoints",
"children":[
{
"target":[
{
"drainPointType":"roundsurface",
"flowType":"normal",
"flowCoefficient":0.5,
"point":{
"x":0,
"y":0
}
}
],
"value":{
"drainPointType":"roundsurface",
"flowType":"normal",
"flowCoefficient":0.5,
"point":{
"x":0,
"y":0
}
},
"property":"0",
"children":[
{
"target":{
"drainPointType":"roundsurface",
"flowType":"normal",
"flowCoefficient":0.5,
"point":{
"x":0,
"y":0
}
},
"value":"roundsurface",
"property":"drainPointType",
"constraints":{
"whitelistValidation":"property drainPointType should not exist"
}
},
{
"target":{
"drainPointType":"roundsurface",
"flowType":"normal",
"flowCoefficient":0.5,
"point":{
"x":0,
"y":0
}
},
"value":"normal",
"property":"flowType",
"constraints":{
"whitelistValidation":"property flowType should not exist"
}
},
{
"target":{
"drainPointType":"roundsurface",
"flowType":"normal",
"flowCoefficient":0.5,
"point":{
"x":0,
"y":0
}
},
"value":0.5,
"property":"flowCoefficient",
"constraints":{
"whitelistValidation":"property flowCoefficient should not exist"
}
},
{
"target":{
"drainPointType":"roundsurface",
"flowType":"normal",
"flowCoefficient":0.5,
"point":{
"x":0,
"y":0
}
},
"value":{
"x":0,
"y":0
},
"property":"point",
"constraints":{
"whitelistValidation":"property point should not exist"
}
}
]
}
]
}
]
The DTO object that contains the array:
export class CreateDrainPointDTO extends DTO {
@IsArray()
@IsNotEmpty()
@ArrayMinSize(1)
@ValidateNested({ each: true })
@Type(() => DrainPointDTO)
drainPoints: DrainPoint[]
}
The Object itself:
export class DrainPointDTO {
@IsString()
@IsOptional()
uuid: string
@IsEnum(DrainPointType)
@IsNotEmpty()
drainPointType: DrainPointType
@IsEnum(DrainPointflowType)
@IsNotEmpty()
flowType: DrainPointflowType
@IsArray()
@IsNotEmpty()
point: Point
@IsNumber()
@IsOptional()
flowCoefficient: number
}
My custom DTO abstract class:
export abstract class DTO {
static async factory<T extends DTO>(Class: new () => T, partial: Partial<T>): Promise<T> {
const dto = Object.assign(new Class(), partial)
const errors = await validate(dto, { whitelist: true, forbidNonWhitelisted: true })
if (errors.length > 0) {
throw new CustomError()
.withError('invalid_parameters')
.withValidationErrors(errors)
}
return dto
}
}
I use this DTO abstract class in order to have a clean way of checking the body inside the controller:
async createDrainPoint (req: Request, res: Response): Promise<void> {
const dto = await DTO.factory(CreateDrainPointDTO, req.body as Partial<CreateDrainPointDTO>)
const drainPoints = await this.drainPointService.create(dto)
res.status(201).json(DrainPointTransformer.array(drainPoints))
}