This is an example of how to ignore a global validation pipe for a specific parameter, e.g. a request body. In fact, this example just shows a request body but you could apply this principle to other decorators.
This approach assumes validateCustomDecorators: false
in the global validation pipe. If validateCustomDecorators
is true in the global pipe I think you're out of luck. If that is your situation, consider refactoring so that validateCustomDecorators
is false in the global pipe and then have each custom decorator add validation if it needs it.
The NestJS ValidationPipe
does not validate custom decorators. So, in this above example we just make a @RawBody()
param decorator, and NestJS will skip validating it.
Take a look at NestJS' ValidationPipe
class at the relevant points:
Here is where it checks to see if the decorator type is 'custom':
https://github.com/nestjs/nest/blob/master/packages/common/pipes/validation.pipe.ts#L164-L166
Here is where it returns if validation shouldn't apply:
https://github.com/nestjs/nest/blob/master/packages/common/pipes/validation.pipe.ts#L102-L106
You could just change the behavior of the global validation pipe. This is a bit tricky and it only works on the param decorator level. First, you need a custom decorator:
export const RawBody = createParamDecorator(
(data: unknown, ctx: ExecutionContext): any => {
const request = ctx.switchToHttp().getRequest();
return request.body;
}
);
Then, you need to build another custom decorator that composes that with a validation pipe like so:
export const ValidBody = () =>
RawBody(
new ValidationPipe({
validateCustomDecorators: true,
whitelist: true,
forbidNonWhitelisted: true,
transform: true,
})
);
Note the use of validateCustomDecorators: true
here! This is important. The validation pipe will not work unless this is true here. (But, remember, validateCustomDecorators
should be false in the global validation pipe.)
Then, use @ValidBody
instead of @Body
wherever you want to override the global validation pipe with your custom validation pipe rules. This approach will work even if there is a global validation pipe.
Instead of applying a global validator, write a custom @Body
decorator (e.g. @ValidBody
) and have that decorator just use a validation pipe; see https://stackoverflow.com/a/56748392/990642. Note: I think validateCustomDecorators: true
would need to be enabled.
Here is an example of the decorator:
export const ValidBody = () =>
Body(
new ValidationPipe({
whitelist: true,
forbidNonWhitelisted: true,
transform: true,
})
);
Then, use @ValidBody
instead of @Body
. This approach does not work if there is a global validation pipe.
Write your own custom ValidationPipe
class, use that globally, and do some checking logic there?
Here are some links that talk about this issue and some documentation links that are relevant:
- https://docs.nestjs.com/techniques/validation
- https://docs.nestjs.com/interceptors
- nestjs/nest#2390
- nestjs/nest#3354
- https://stackoverflow.com/questions/58751743/disable-validation-in-nestjs-param-decorator?rq=1
- https://stackoverflow.com/questions/54471331/how-to-ignore-an-interceptor-for-a-particular-route-in-nestjs
- https://stackoverflow.com/questions/56273543/how-to-override-global-validationpipe-in-controller
- https://stackoverflow.com/questions/56583609/how-can-we-override-the-global-validation-pipe-in-nestjs
Thanks mate !