NestJs - Validate request body using class-validator having 2 options for body class

Viewed 5445

I have a rest call, which might receive body of type classA or classB. I need to keep it as 2 different classes. Example -

// classes -
class ClassA {
    @IsString()
    @Length(1, 128)
    public readonly name: string;
    @IsString()
    @Length(1, 128)
    public readonly address: string;
}

class ClassB {
    @IsString()
    @Length(1, 10)
    public readonly id: string;
}


// my request controller - 

    @Post('/somecall')
    public async doSomething(
        @Body(new ValidationPipe({transform: true})) bodyDto: (ClassA | ClassB) // < not validating any of them..
    ): Promise<any> {
// do something
    }

The issue is, that when having more than one class, body is not validated.

How can I use 2 or more classes and validate them using class-validator? I don't want to use same class..

Thank you all :)

2 Answers

I don't want to use same class..

Then it won't be possible, at least not with Nest's built-in ValidationPipe. Typescript doesn't reflect unions, intersections, or other kinds of generic types, so there's no returned metadata for this parameter, and if there's no metadata that's actionable Nest will end up skipping the pipe.

You could probably create a custom pipe to do the validation for you, and if you have two types you're probably going to have to. You can still call the appropriate class-transformer and class-validator methods inside of the class too.

import { CallHandler, ExecutionContext, Injectable, NestInterceptor } from '@nestjs/common';
import { of } from 'rxjs';

@Injectable()
export class CheckTypeInterceptor implements NestInterceptor {
    constructor() {}

    async intercept(context: ExecutionContext, next: CallHandler) /*: Observable<any>*/ {
        const httpContext = context.switchToHttp();
        const req = httpContext.getRequest();
        const bodyDto = req.body.bodyDto;

        // Need Update below logic
        if (bodyDto instanceof ClassA || bodyDto instanceof ClassB) {
            return next.handle();
        }

        // Return empty set
        return of([]);
    }
}
@UseInterceptors(CheckTypeInterceptor)
export class ApiController {
   ...
}
Related