基本使用
Post 请求的数据是通过 @Body
装饰器来取,并且要有一个 dto class 来接收:
DTO(Data Transfer Object)数据传输对象,定义客户端发送到服务器的数据结构,通常在处理 HTTP 请求时使用。
使用 postman 发送 post 请求:
点击 send,服务端就接收到数据了:
如果 age 传一个浮点数,服务端也能正常接收:
因为它也是 number。
如果想要更精细的数字验证,就需要 ValidationPipe。
它需要两个依赖包:
bash
npm install class-validator class-transformer -D
dto里面用 @IsInt
装饰器标记整数:
再次请求,就会检查参数了:
ValidationPipe 实现原理
那它是怎么实现的呢?
class-validator 包允许使用装饰器来添加验证规则到类属性的库
而 class-transformer 包允许通过装饰器将普通的 JavaScript 对象转换成类的实例的库。同时,它也支持将类的实例转换回普通的 JavaScript 对象。
这两者结合:
- 我们声明了参数的类型为 dto 类,pipe 里拿到这个类
- 把参数对象通过 class-transformer 转换为 dto 类的对象,之后再用 class-validator 包来对这个对象做验证。
typescript
import {
PipeTransform,
Injectable,
ArgumentMetadata,
BadRequestException,
} from '@nestjs/common';
import { validate } from 'class-validator';
import { plainToInstance } from 'class-transformer';
@Injectable()
export class MyValidationPipe implements PipeTransform<any> {
async transform(value: any, { metatype }: ArgumentMetadata) {
if (!metatype) {
return value;
}
const object = plainToInstance(metatype, value);
const errors = await validate(object);
if (errors.length > 0) {
throw new BadRequestException('参数验证失败');
}
return value;
}
}
先拿到 metatype
也就是 Ooo 类型。
通过 plainToInstance
把普通对象转换为 dto class 的实例对象。
调用 validate 对它做验证。如果验证不通过,就抛一个异常。
替换为我们自己实现的 MyValidationPipe 后请求下:
同样报错。
pipe 注入依赖和全局 pipe
pipe 里也是可以注入依赖的:
比如,我们指定 @Inject 注入,因为标记了 @Optional,没找到对应的 provider 也不会报错。
如果标记了 @Optional 就不能用 new 的方式了,直接指定 class,让 Nest 去创建对象放到 ioc 容器里。
当我们在 module 里添加了这个 provider :
这样就可以正常注入了:
如果注册为全局的 pipe:
其余的 filter、guard、interceptor 也可以通过这种方式声明为全局生效的。
此时方法里面去掉 ValidationPipe 依然会生效:
如果我们不注入依赖,这种方式也可以声明全局 pipe:
class-validator 验证方式
我们声明这样一个 dto class:
添加路由:
参数不正确:
参数正确:
这个错误消息还可以有更多信息:
更多校验装饰器可以看 class-validator 文档。