7

I'm trying to validate array of nested objects in nestjs and it works fine. But if I send non-array value like string or null, then I get an error:

TypeError: Cannot read property 'length' of undefined.

Nested field:

@IsArray()
@ValidateNested({ each: true })
@Type(() => NestedDTO)
nested: NestedDTO[];

How can I validate that value is an array before validate nested objects?

Versions:

NestJS: 6.10.14
class-validator: 0.11.0
3
  • welcome to the community, please share with us your class-validator && nestjs version. Commented Feb 21, 2020 at 10:37
  • Thanks! Updated. NestJS: 6.10.14 class-validator: 0.11.0 Commented Feb 21, 2020 at 11:06
  • ValidateNested() doesn't work with custom objects Commented Feb 21, 2020 at 14:45

1 Answer 1

3

Out-of-the-box support for validation of array of objects is kind of scarce in NestJS so far.

Please have at look at my solution:

The main point is to write and then to use your custom IsArrayOfObjects decorator that will contain the validation logic + @Type decorator from class-transformer module.

import { Type } from 'class-transformer';
import {
  IsString,
  registerDecorator,
  ValidateNested,
  ValidationArguments,
  ValidationOptions,
} from 'class-validator';

export function IsArrayOfObjects(validationOptions?: ValidationOptions) {
  return (object: unknown, propertyName: string) => {
    registerDecorator({
      name: 'IsArrayOfObjects',
      target: object.constructor,
      propertyName,
      constraints: [],
      options: validationOptions,
      validator: {
        validate(value: any): boolean {
          return (
            Array.isArray(value) &&
            value.every(
              (element: any) =>
                element instanceof Object && !(element instanceof Array),
            )
          );
        },
        defaultMessage: (validationArguments?: ValidationArguments): string =>
          `${validationArguments.property} must be an array of objects`,
      },
    });
  };
}

Suppose we have this NestedDTO:

export class NestedDTO {
  @IsString()
  someProperty: string;
}

Then we can simply use it for defining like:

@IsArrayOfObjects()
@ValidateNested()
@Type(() => NestedDTO)
nested: NestedDTO[];

However, this solution will allow empty array to be passed. Then you can add extra condition in IsArrayOfObjects like value.length > 0 and also correct its defaultMessage.

Sign up to request clarification or add additional context in comments.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.