Nest.js系列——内置 Pipe 和自定义 Pipe

在 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 的工作方式有一个自己的理解,希望这个文章对你有帮助,多谢支持。

相关推荐
高频因子挖掘机14 分钟前
量化回测应该保存不复权数据吗?从数据口径到收益计算的工程实践
后端·github·api
高频因子挖掘机1 小时前
实时行情为什么不应该逐只股票请求?批量查询与标的池管理实践
后端·github·api
程序猿DD6 小时前
OctaFuse Gateway 2.15.0:MCP 聚合、向量 Embeddings 与官方目录同步
后端·agent
余槐i9 小时前
PostgreSQL 函数索引报错 must be immutable:3种绕法与代价
数据库·后端·sql·postgresql·性能优化
需要8269 小时前
Spring Bean 生命周期:从实例化到销毁的完整钩子
java·后端·spring
凤山老林10 小时前
Spring Boot 接入国密 SM2/SM3/SM4 的一些实践记录
spring boot·后端·python
伯恩bourne11 小时前
Spring Boot Bean 注册的两种方式:@Component 家族 vs @Configuration + @Bean
java·spring boot·后端
张彦峰ZYF12 小时前
停顿短不等于延迟低:G1、ZGC 与低延迟服务的目标分野、代价账本与选型标定
后端·回收暂停、应用停止总时长·到达安全点、分配停滞·屏障吃吞吐、并发线程吃核心·并发窗口吃堆余量·分区式靠挑回收集兑现目标·染色指针式不支持压缩引用
pride.li12 小时前
第03章 Python 教程-基础语法:注释与变量
服务器·前端·后端·python·算法·计算机视觉
DevUp12 小时前
标着 JavaScript 的 Wiki 与知识库:既不是 CMS 也不是 SSG(番外三)
javascript·node.js·cms