Last active
June 18, 2025 06:36
-
-
Save josephdpurcell/9af97c36148673de596ecaa7e5eb6a0a to your computer and use it in GitHub Desktop.
Revisions
-
josephdpurcell revised this gist
Nov 19, 2021 . 1 changed file with 2 additions and 2 deletions.There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode charactersOriginal file line number Diff line number Diff line change @@ -39,7 +39,7 @@ Then, you need to build another custom decorator that composes that with a valid ```ts export const ValidBody = () => RawBody( new ValidationPipe({ validateCustomDecorators: true, whitelist: true, forbidNonWhitelisted: true, @@ -62,7 +62,7 @@ Here is an example of the decorator: ```ts export const ValidBody = () => Body( new ValidationPipe({ whitelist: true, forbidNonWhitelisted: true, transform: true, -
josephdpurcell revised this gist
Nov 19, 2021 . 1 changed file with 1 addition and 1 deletion.There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode charactersOriginal file line number Diff line number Diff line change @@ -21,7 +21,7 @@ https://github.com/nestjs/nest/blob/master/packages/common/pipes/validation.pipe # Are there alternative approaches? ## Alternate 1: Use @ValidBody with custom overrides to the global ValidationPipe 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: -
josephdpurcell revised this gist
Nov 19, 2021 . 1 changed file with 56 additions and 3 deletions.There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode charactersOriginal file line number Diff line number Diff line change @@ -2,6 +2,8 @@ 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. # How does this work? 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. @@ -18,10 +20,61 @@ https://github.com/nestjs/nest/blob/master/packages/common/pipes/validation.pipe # Are there alternative approaches? ## Alternate 1: Override global ValidationPipe 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: ```ts 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: ```ts export const ValidBody = () => RawBody( new MyValidationPipe({ 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. ## Alternate 2: Use @ValidBody instead of global ValidationPipe 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: ```ts export const ValidBody = () => Body( new MyValidationPipe({ whitelist: true, forbidNonWhitelisted: true, transform: true, }) ); ``` Then, use `@ValidBody` instead of `@Body`. This approach does not work if there is a global validation pipe. ## Alternate 3: Custom ValidationPipe Write your own custom `ValidationPipe` class, use that globally, and do some checking logic there? # Links -
josephdpurcell revised this gist
Nov 19, 2021 . 1 changed file with 4 additions and 0 deletions.There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode charactersOriginal file line number Diff line number Diff line change @@ -1,3 +1,7 @@ # What is this? 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. # How does this work? 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. -
josephdpurcell revised this gist
Nov 19, 2021 . 1 changed file with 7 additions and 0 deletions.There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode charactersOriginal file line number Diff line number Diff line change @@ -12,6 +12,13 @@ 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 # Are there alternative approaches? I haven't thoroughly researched this, but here are a few that come to mind: * 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 * Write your own custom `ValidationPipe` class, use that globally, and do some checking logic there? # Links Here are some links that talk about this issue and some documentation links that are relevant: -
josephdpurcell renamed this gist
Nov 19, 2021 . 1 changed file with 0 additions and 0 deletions.There are no files selected for viewing
File renamed without changes. -
josephdpurcell created this gist
Nov 19, 2021 .There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode charactersOriginal file line number Diff line number Diff line change @@ -0,0 +1,26 @@ # How does this work? 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 # Links 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 * https://github.com/nestjs/nest/issues/2390 * https://github.com/nestjs/nest/pull/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 This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode charactersOriginal file line number Diff line number Diff line change @@ -0,0 +1,11 @@ import { ValidationPipe } from '@nestjs/common'; // ... app.useGlobalPipes(new ValidationPipe({ whitelist: true, forbidNonWhitelisted: true, transform: true, })); // ... This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode charactersOriginal file line number Diff line number Diff line change @@ -0,0 +1,13 @@ import { Body, Controller, Post } from '@nestjs/common'; import { RawBody } from './raw-body.ts'; import { MyDto } from './my.dto'; @Controller() export class MyController { @Post() async post( @RawBody() params: MyDto ): Promise<void> { // params will be a raw un-typed object with no validation having been run on it! } } This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode charactersOriginal file line number Diff line number Diff line change @@ -0,0 +1,6 @@ import { IsNotEmpty } from "class-validator"; export class MyDto { @IsNotEmpty() field: string; } This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode charactersOriginal file line number Diff line number Diff line change @@ -0,0 +1,8 @@ import { createParamDecorator, ExecutionContext } from '@nestjs/common'; export const RawBody = createParamDecorator( (data: unknown, ctx: ExecutionContext): any => { const request = ctx.switchToHttp().getRequest(); return request.body; } );