class-validator
class-validator copied to clipboard
question: how to validate a nested object with unknown keys but known value properties
Hi, I'm trying to validate this model and the Nested
part is not validate properly :
export class Nested {
@IsString()
name: string;
}
export class Test{
@IsString()
id: string;
@IsObject()
@ValidateNested()
@Type(() => Nested)
@prop()
nestedElements: {
[category: string]: Nested;
}
}
The actual object can have multiples unknown categories
{
"id":"test",
"nestedElements": {
"music" : { name: "test" },
"art" : { name: "test" }
}
}
I'm not sure if this is possible ?
For now I'm doing this custom validator (temporary) to ensure it's validated
@ValidatorConstraint()
export class IsNestedElementsConstraint implements ValidatorConstraintInterface {
public async validate(value: any, args: ValidationArguments) {
const validations = [];
Object.entries(value).forEach(entry => {
validations.push(validate(plainToClass(Nested, entry[1])));
});
const process = await Promise.all(validations);
return process.every(p => p.length <= 0);
}
public defaultMessage(args: ValidationArguments) {
return `${args.property} error`;
}
}
export const IsNestedElements = (validationOptions?: ValidationOptions) => {
return (object: object, propertyName: string) => {
registerDecorator({
target: object.constructor,
propertyName,
options: validationOptions,
constraints: [],
validator: IsNestedElementsConstraint
});
};
};
export class Test{
@IsString()
id: string;
@IsNestedElements()
@prop()
nestedElements: {
[category: string]: Nested;
}
}
Is there a better / more generic way ? Thanks !
Same question
You can make it more generic by getting rid of Nested class (as in picture). Cannot find any reasonable solution in docs/issues for the presented problem and creating such complicated custom validator is not user friendly. I think it's a great code that should be considered to merge as a base validator.
@johny1614 yep agreed, I could make a PR but i'm not sure when it's gonna be merge, still waiting on some PR from last year to be released on this repo (about the groups for ex.). It's too bad the maintainers are not super active also because our application is heavily using class validator
If someone want to achieve both transformation and validation you can use this:
import { ClassConstructor, Type, TypeHelpOptions, TypeOptions } from 'class-transformer';
import {
registerDecorator,
validate,
ValidateNested,
ValidationArguments,
ValidationOptions,
ValidatorConstraintInterface,
} from 'class-validator';
// taken from - import { applyDecorators } from '@nestjs/common';
function applyDecorators(
...decorators: Array<PropertyDecorator>
) {
return <TFunction extends Function, Y>(
target: TFunction | object,
propertyKey?: string | symbol,
) => {
for (const decorator of decorators) {
decorator(
target,
propertyKey,
);
}
};
}
const TYPESCRIPT_DECORATE_DESIGN_TYPE = 'design:type';
class IsRecordConstraint implements ValidatorConstraintInterface {
public async validate(value: any): Promise<boolean> {
const validationResults = await Promise.all(Object.entries(value).map((entry) => validate(entry[1] as object)));
return validationResults.every((p) => p.length <= 0);
}
public defaultMessage(args: ValidationArguments) {
return `${args.property} error`;
}
}
const validator = new IsRecordConstraint();
const IsRecordValidator =
(validationOptions?: ValidationOptions): PropertyDecorator =>
(object: object, propertyName: string | symbol) => {
registerDecorator({
target: object.constructor,
propertyName: propertyName as string,
options: validationOptions,
constraints: [],
validator,
});
};
export const IsRecord = <T extends object>(
type: ClassConstructor<T>,
validationOptions?: ValidationOptions,
typeOptions?: TypeOptions,
): PropertyDecorator =>
applyDecorators(
ValidateNested(),
IsRecordValidator(),
Type((options?: TypeHelpOptions) => {
class RecordClass {}
Object.entries(options?.object?.[options?.property]).forEach(([key]) => {
const decorators = [
ValidateNested(validationOptions),
Type(() => type, typeOptions),
Reflect.metadata(TYPESCRIPT_DECORATE_DESIGN_TYPE, Object),
];
Reflect.decorate(decorators, RecordClass.prototype, key, undefined);
});
return RecordClass;
}),
);
The class-validator
package is currently not well suited for validating classes with dynamically changing content.
This issue has been automatically locked since there has not been any recent activity after it was closed. Please open a new issue for related bugs.