Skip to content

Commit b632f60

Browse files
Merge pull request nestjs#1348 from nestjs/feature/1267-validation-factory
feature(common) add validation error factory (ValidationPipe)
2 parents c6ec887 + ee9d316 commit b632f60

4 files changed

Lines changed: 47 additions & 7 deletions

File tree

packages/common/index.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,7 @@ export {
4040
Provider,
4141
RpcExceptionFilter,
4242
Type,
43+
ValidationError,
4344
WebSocketAdapter,
4445
WsExceptionFilter,
4546
} from './interfaces';
Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
/**
2+
* Validation error description.
3+
* @see https://github.com/typestack/class-validator
4+
*/
5+
export interface ValidationError {
6+
/**
7+
* Object that was validated.
8+
*/
9+
target: Object;
10+
/**
11+
* Object's property that haven't pass validation.
12+
*/
13+
property: string;
14+
/**
15+
* Value that haven't pass a validation.
16+
*/
17+
value: any;
18+
/**
19+
* Constraints that failed validation with error messages.
20+
*/
21+
constraints: {
22+
[type: string]: string;
23+
};
24+
/**
25+
* Contains all nested validation errors of the property.
26+
*/
27+
children: ValidationError[];
28+
}

packages/common/interfaces/index.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ export * from './controllers/controller.interface';
44
export * from './exceptions/exception-filter.interface';
55
export * from './exceptions/rpc-exception-filter.interface';
66
export * from './exceptions/ws-exception-filter.interface';
7+
export * from './external/validation-error.interface';
78
export * from './features/arguments-host.interface';
89
export * from './features/can-activate.interface';
910
export * from './features/custom-route-param-factory.interface';

packages/common/pipes/validation.pipe.ts

Lines changed: 17 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,19 @@
11
import { Optional } from '../decorators';
2-
import { ArgumentMetadata, BadRequestException } from '../index';
2+
import { Injectable } from '../decorators/core/component.decorator';
3+
import {
4+
ArgumentMetadata,
5+
BadRequestException,
6+
ValidationError,
7+
} from '../index';
38
import { ValidatorOptions } from '../interfaces/external/validator-options.interface';
49
import { PipeTransform } from '../interfaces/features/pipe-transform.interface';
510
import { loadPackage } from '../utils/load-package.util';
611
import { isNil } from '../utils/shared.utils';
7-
import { Injectable } from '../decorators/core/component.decorator';
812

913
export interface ValidationPipeOptions extends ValidatorOptions {
1014
transform?: boolean;
1115
disableErrorMessages?: boolean;
16+
exceptionFactory?: (errors: ValidationError[]) => any;
1217
}
1318

1419
let classValidator: any = {};
@@ -19,13 +24,20 @@ export class ValidationPipe implements PipeTransform<any> {
1924
protected isTransformEnabled: boolean;
2025
protected isDetailedOutputDisabled?: boolean;
2126
protected validatorOptions: ValidatorOptions;
27+
protected exceptionFactory: (errors: ValidationError[]) => any;
2228

2329
constructor(@Optional() options?: ValidationPipeOptions) {
2430
options = options || {};
2531
const { transform, disableErrorMessages, ...validatorOptions } = options;
2632
this.isTransformEnabled = !!transform;
2733
this.validatorOptions = validatorOptions;
2834
this.isDetailedOutputDisabled = disableErrorMessages;
35+
this.exceptionFactory =
36+
options.exceptionFactory ||
37+
(errors =>
38+
new BadRequestException(
39+
this.isDetailedOutputDisabled ? undefined : errors,
40+
));
2941

3042
const loadPkg = pkg => loadPackage(pkg, 'ValidationPipe');
3143
classValidator = loadPkg('class-validator');
@@ -43,15 +55,13 @@ export class ValidationPipe implements PipeTransform<any> {
4355
);
4456
const errors = await classValidator.validate(entity, this.validatorOptions);
4557
if (errors.length > 0) {
46-
throw new BadRequestException(
47-
this.isDetailedOutputDisabled ? undefined : errors,
48-
);
58+
throw this.exceptionFactory(errors);
4959
}
5060
return this.isTransformEnabled
5161
? entity
5262
: Object.keys(this.validatorOptions).length > 0
53-
? classTransformer.classToPlain(entity)
54-
: value;
63+
? classTransformer.classToPlain(entity)
64+
: value;
5565
}
5666

5767
private toValidate(metadata: ArgumentMetadata): boolean {

0 commit comments

Comments
 (0)