概念
管道
是具有@Injectable
装饰器的类
管道
应实现PineTransform
接口
管道可以是参数级,方法级,控制器级,全局级
管道原理
管道
有两种类型:
-
转换
:管道将输入数据转换成所需的数据输出 -
验证
:对输入数据进行验证,成功则继续传递,失败则抛出异常
Nest
会在Controller的路由处理程序
之前插入一个管道,Nest会拦截该方法的调用参数
,进行转换
/验证
处理,然后再调用原方法。
内置管道
@nestjs/common
自带五个开箱即用的管道:ValidationPipe
、ParseIntPipe
、ParseBoolPipe
、ParseArrayPipe
、ParseUUIDPipe
.
某个场景
//create-cat.dto
export class CreateCatDto {
name: string;
age: number;
breed: string;
}
//cats.controller.ts
@Post()
async create(@Body() createCatDto: CreateCatDto) {
this.catsService.create(createCatDto);
}
为了确保create()的正确执行,必须验证CreateCatDto的三个属性。此时可考虑验证管道
。
- 控制器路由处理程序中验证(不好);
- 创建验证器类并委托任务(不好);
- 验证中间件(不好);
验证管道:第一种验证方式
创建自定义的验证管道
Joi库
是一个基于结构的验证库。
//安装依赖
$ npm install --save @hapi/joi
$ npm install --save-dev @types/hapi__joi
//自定义一个验证管道
import { PipeTransform, Injectable, ArgumentMetadata, BadRequestException } from '@nestjs/common';
import { ObjectSchema } from '@hapi/joi';
@Injectable()
export class JoiValidationPipe implements PipeTransform {
constructor(private schema: ObjectSchema) {}
transform(value: any, metadata: ArgumentMetadata) {
const { error } = this.schema.validate(value);
if (error) {
throw new BadRequestException('Validation failed');
}
return value;
}
}
绑定管道(应用管道)
@Post()
@UsePipes(new JoiValidationPipe(createCatSchema))
async create(@Body() createCatDto: CreateCatDto) {
this.catsService.create(createCatDto);
}
- 管道可以绑在
controller
或是其方法
上 -
@UsePipes() 装饰器
并创建一个管道实例,并将其传递给Joi
验证
验证管道:第二种验证方式
class-validator
允许基于装饰器的验证,可以通过metatype
做很多事.
$ npm i --save class-validator class-transformer
创建相关DTO
//向CreateCatDto类添加一些装饰器
import { IsString, IsInt } from 'class-validator';
export class CreateCatDto {
@IsString()
name: string;
@IsInt()
age: number;
@IsString()
breed: string;
}
创建自定义的验证管道
//创建ValidationPipe 类
import { PipeTransform, Injectable, ArgumentMetadata, BadRequestException } from '@nestjs/common';
import { validate } from 'class-validator';
import { plainToClass } from 'class-transformer';
@Injectable()
export class ValidationPipe implements PipeTransform {
//1. transform()是异步的,因为有些class-validator的验证是Promise(异步的)
//2. metatype采用解构赋值从ArgumentMetadata中提取参数
async transform(value: any, { metatype }: ArgumentMetadata) {
//当验证类型不是js的数据类型时,跳过验证
if (!metatype || !this.toValidate(metatype)) {
return value;
}
//因为请求body中不包含类型信息,若class-validator需要使用相关的DTO,需要做类型转换
const object = plainToClass(metatype, value);
const errors = await validate(object);
if (errors.length > 0) {
throw new BadRequestException('Validation failed');
}
return value;
}
private toValidate(metatype: Function): boolean {
const types: Function[] = [String, Boolean, Number, Array, Object];
return !types.includes(metatype);
}
}
应用管道(参数级别)
//cats.controller.ts
@Post()
async create(@Body(new ValidationPipe()) createCatDto: CreateCatDto) {
this.catsService.create(createCatDto);
}
应用管道(方法级别)
//cats.controller.ts
@Post()
@UsePipes(new ValidationPipe()) //ValidationPipe 的实例已就地立即创建
async create(@Body() createCatDto: CreateCatDto) {
this.catsService.create(createCatDto);
}
//cats.controller.ts
@Post()
@UsePipes(ValidationPipe) //直接传入类(而非实例),让框架承担实例化责任,并启用依赖注入
async create(@Body() createCatDto: CreateCatDto) {
this.catsService.create(createCatDto);
}
应用管道(全局级别)
//main.ts
async function bootstrap() {
const app = await NestFactory.create(AppModule);
app.useGlobalPipes(new ValidationPipe()); //用于整个应用程序、每个控制器和每个路由处理程序
await app.listen(3000);
}
bootstrap();
转换管道
- 从
transform
函数返回的值完全覆盖了参数先前的值
定义转换管道
// parse-int.pipe.ts
import { PipeTransform, Injectable, ArgumentMetadata, BadRequestException } from '@nestjs/common';
@Injectable()
export class ParseIntPipe implements PipeTransform {
transform(value: string, metadata: ArgumentMetadata): number {
const val = parseInt(value, 10);
if (isNaN(val)) {
throw new BadRequestException('Validation failed');
}
return val;
}
}
应用管道
@Get(':id')
async findOne(@Param('id', new ParseIntPipe()) id) {
return await this.catsService.findOne(id);
}
//@Param('id', new ParseIntPipe()) id 的用法?
-
ParseIntpipe
将在请求触发相应的处理程序之前
执行。
内置验证管道
-
ValidationPipe
和ParseIntPipe
是内置管道,不必自己构建这些管道 -
ValidationPipe
需要同时安装class-validator
和class-transformer
包