在 NestJS 框架中,Pipe 是一个强大的功能,用于在请求处理程序执行之前验证和转换数据。就是在参数传递到处理函数之前做一些验证和转换处理的 class,NestJS 内置了一系列常用的 Pipe,并且允许开发者根据需求创建自定义 Pipe。下面我们将介绍各种内置 Pipe 的使用例子,并展示如何实现一个自定义 Pipe。内置的 Pipe 有这些:
ValidationPipe
ParseIntPipe
ParseBoolPipe
ParseArrayPipe
ParseUUIDPipe
ParseEnumPipe
ParseFilePipe
ParseFloatPipe
DefaultValuePipe
ValidationPipe
在 NestJS 中,ValidationPipe
用于自动执行输入数据验证。这通常与类类型 (DTO - Data Transfer Objects) 一起使用。一般依赖与两个库来实现class-validator
和 class-transformer
.
class-validator
和 class-transformer
是两个在 TypeScript
和 JavaScript
项目中经常联合使用的库,它们提供了一套装饰器和一些函数来实现数据的验证和转换功能。在许多服务器端框架中,尤其是在 NestJS
中,这两个库用来处理和验证客户端发送到服务器的数据并进行类型转换。
在项目中一般会全局开启这个管道来对数据进行验证
ts
// 全局管道
app.useGlobalPipes(new ValidationPipe())
ParseIntPipe
在路由中拿参数一般情况下是 string 类型,ParseIntPipe
就对拿到的数据进行转换,简单的用法就是直接在控制器方法中添加管道
ts
@Get()
getHello(@Query('water', ParseIntPipe) water: string): string {
return water;
}
通过这个管道,可以将字符串类型的参数转化为数字类型
如果传递的参数是不能转化为数字类型的话,那么就是会报错了。 可以看到这里的错误吗是 400,其实这个错误码是可以更改的,改变下管道的调用方式加一些参数。
ts
@Get('water')
getWater(
@Query(
'water',
new ParseIntPipe({
errorHttpStatusCode: HttpStatus.NOT_FOUND,
}),
)
water: string,
): string {
return water;
}
然后调用下这个接口,看下返回结果是什么 由图中可以看出状态码已经更改为 404 了。当然也可以直接抛出一个错误,让过滤器去拦截,或者使用自定义过滤器处理。
ts
@Get('error')
getError(
@Query(
'water',
new ParseIntPipe({
exceptionFactory(error) {
console.log(error);
throw new HttpException('xxx ' + error, HttpStatus.NOT_IMPLEMENTED);
},
}),
)
water: string,
): string {
return water;
}
在调用下就能看到错误信息已经改变
ParseFloatPipe
这个管道是转换为浮点数的,可以使用下看看效果
ts
@Get('water-float')
getFloat(@Query('water', ParseFloatPipe) water: number) {
return water + 2;
}
看下访问的结果 类型为字符串的参数被转换为浮点数并做了计算。
ParseBoolPipe
通过这个管道把参数值转换为布尔值
ts
@Get('water-bool')
getBool(@Query('water', ParseBoolPipe) water: boolean) {
return water;
}
但是能转换的值有限只接受严格的'true'、'false',其他传入的参数会报错
ParseArrayPipe
这个管道会把传入的参数按照一定的规则解析成数组类型,但是这个依赖class-validator
、class-transformer
这两个包,前面已经安装过了。
ts
@Get('water-arr')
getArr(
@Query(
'water',
new ParseArrayPipe({
items: Number,
}),
)
water: Array<number>,
) {
return water;
}
调用这个接口传入参数看返回的解析后结果
这里使用的时候可以看到,传入了一个参数为items: Number
,其实这个就是把数组的每个元素设置为数字,如果不设置这个参数的话返回的会是字符串数组,来实验一下,
ts
@Get('water-arr')
getArr(
@Query(
'water',
ParseArrayPipe
)
water: Array<number>,
) {
return water;
}
再次访问下,看返回结果:
但是这里,还有个问题,如果不传参数就会报错,其实也是有配置可以解决的,配置一下
ts
@Get('water-arr')
getArr(
@Query(
'water',
new ParseArrayPipe({
items: Number,
optional: true,
}),
)
water: Array<number>,
) {
return water;
}
这样就不会报错了,但是解析数组有时候还会有一种情况,比如前后端约定转换时候不是安装,
来进行切割的,比如按照;
那就需要有改变,这里也是支持指定的,来配置一下
ts
@Get('water-arr')
getArr(
@Query(
'water',
new ParseArrayPipe({
items: Number,
separator: ';',
optional: true,
}),
)
water: Array<number>,
) {
return water;
}
调用下看返回结果
ParseUUIDPipe
这个就比较简单了,可以转换判断下参数是不是 uuid
ts
@Get('water-uuid')
getUuid(@Query('water', ParseUUIDPipe) water: string) {
return water;
}
ParseEnumPipe
这个管道可以限制传递的参数必须是枚举中的值,如果不是就会报错
ts
enum E {
AAA = '111',
}
@Get('water-enmu')
getEnmu(@Query('water', new ParseEnumPipe(E)) water: E) {
return water;
}
DefaultValuePipe
这个管道可以用来设置默认值,如果没有没有传递任何参数那么就用默认值
ts
@Get('water-df')
getDf(@Query('water', new DefaultValuePipe('water')) water: string) {
return water;
}
如果有参数则使用传递的参数
自定义 pipe
以上就是这些内置的 pipe,可以满足一些日常使用,但是很显然,有时候有一些特殊的需求需要自定义一些 pipe,这里就简单写一个自定义的 pipe,先了解如何定义一个自定义的 pipe。先使用 cli 自带的命令创建一个自定义的 pipe。
shell
nest g pipe custom-pipe --flat --no-spec
这个命令会在项目根目录下生成一个 pipe 文件
shell
- custom-pipe.pipe.ts
默认生成一个简单的 pipe 代码
ts
import { ArgumentMetadata, Injectable, PipeTransform } from '@nestjs/common'
@Injectable()
export class CustomPipePipe implements PipeTransform {
transform(value: any, metadata: ArgumentMetadata) {
console.log(value, metadata)
return value
}
}
这里面加了一行打印日志,看一看接受的内容是什么,然后先写一个接口调用下这个自定义的 pipe。
ts
import { CustomPipePipe } from './custom-pipe.pipe';
@Get('custom-pipe')
getCustomPipe(@Query('water', CustomPipePipe) water: string) {
return water;
}
调用下这个接口,看看返回值
再来看看自定义的 pipe 中答应的 log 是什么
由以上可以看出,pipe 中能够获取到请求参数的类型,和获取参数的方式以及参数的值,在这个里面做一些自定义的操作就行了。这就是一个简单的自定义 pipe。
小结
这里简单介绍了 nest 中内置的 pipe 和简单实现了一个自定义的 pipe,这样能够对 pipe 的工作方式有一个自己的理解,希望这个文章对你有帮助,多谢支持。