/
validation.pipe.ts
88 lines (80 loc) 路 2.99 KB
/
validation.pipe.ts
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
import { Optional } from '../decorators';
import { Injectable } from '../decorators/core';
import { ArgumentMetadata, BadRequestException, ValidationError } from '../index';
import { ClassTransformOptions } from '../interfaces/external/class-transform-options.interface';
import { ValidatorOptions } from '../interfaces/external/validator-options.interface';
import { PipeTransform } from '../interfaces/features/pipe-transform.interface';
import { loadPackage } from '../utils/load-package.util';
import { isNil } from '../utils/shared.utils';
export interface ValidationPipeOptions extends ValidatorOptions {
transform?: boolean;
disableErrorMessages?: boolean;
transformOptions?: ClassTransformOptions;
exceptionFactory?: (errors: ValidationError[]) => any;
}
let classValidator: any = {};
let classTransformer: any = {};
@Injectable()
export class ValidationPipe implements PipeTransform<any> {
protected isTransformEnabled: boolean;
protected isDetailedOutputDisabled?: boolean;
protected validatorOptions: ValidatorOptions;
protected transformOptions: ClassTransformOptions;
protected exceptionFactory: (errors: ValidationError[]) => any;
constructor(@Optional() options?: ValidationPipeOptions) {
options = options || {};
const {
transform,
disableErrorMessages,
transformOptions,
...validatorOptions
} = options;
this.isTransformEnabled = !!transform;
this.validatorOptions = validatorOptions;
this.transformOptions = transformOptions;
this.isDetailedOutputDisabled = disableErrorMessages;
this.exceptionFactory =
options.exceptionFactory ||
(errors =>
new BadRequestException(
this.isDetailedOutputDisabled ? undefined : errors,
));
classValidator = loadPackage('class-validator', 'ValidationPipe', () =>
require('class-validator'),
);
classTransformer = loadPackage('class-transformer', 'ValidationPipe', () =>
require('class-transformer'),
);
}
public async transform(value: any, metadata: ArgumentMetadata) {
const { metatype } = metadata;
if (!metatype || !this.toValidate(metadata)) {
return value;
}
const entity = classTransformer.plainToClass(
metatype,
this.toEmptyIfNil(value),
this.transformOptions
);
const errors = await classValidator.validate(entity, this.validatorOptions);
if (errors.length > 0) {
throw this.exceptionFactory(errors);
}
return this.isTransformEnabled
? entity
: Object.keys(this.validatorOptions).length > 0
? classTransformer.classToPlain(entity, this.transformOptions)
: value;
}
private toValidate(metadata: ArgumentMetadata): boolean {
const { metatype, type } = metadata;
if (type === 'custom') {
return false;
}
const types = [String, Boolean, Number, Array, Object];
return !types.some(t => metatype === t) && !isNil(metatype);
}
toEmptyIfNil<T = any, R = any>(value: T): R | {} {
return isNil(value) ? {} : value;
}
}