介绍
在nest中,校验参数是非常常用的功能,nest中也有许多内置的校验,通过管道来执行,但是在实际项目开发中,用的最多的还是通过ValidationPipe来实现自定义管道,那么下面就让我们来看下内置管道和自定义管道的实际应用吧。
内置管道验证
nest内置管道有这些:
- ValidationPipe
- ParseIntPipe
- ParseBoolPipe
- ParseArrayPipe
- ParseUUIDPipe
- DefaultValuePipe
- ParseEnumPipe
- ParseFloatPipe
- ParseFilePipe
使用内置管道验证
现在我们对getHello接口增加一个name参数,如果我们不增加参数验证的话,无论是字符串还是数字或者浮点数都可以接收到,如下:
@Get()
getHello(@Query('name') name: string): string {
return name;
}
输入数字111能够正常返回:
输入字符串 野克 也能够正常返回:
但是如果我们给参数增加ParseIntPipe验证的话,就只能接受int类型参数,否则就返回报错信息,如下:
getHello(@Query('name', ParseIntPipe) name: string): string {
return name;
}
输入数字123能够正常返回:
输入字符串 野克 就报错了:
是不是非常的简单!
接下来让我们来看下ParseIntPipe管道还能怎么玩
我们按住Ctrl或者command 点击 ParseIntPipe,进入ParseIntPipe的类型声明,如下图:
我们可以看到有个 options 参数,参数类型有三个:errorHttpStatusCode、exceptionFactory、optional
欧吼?意思是我们可以自定义错误状态码或者返回自定义函数,让我们来试下:
默认错误的返回code是400,现在我们让其返回502:
@Get()
getHello(
@Query(
'name',
new ParseIntPipe({
errorHttpStatusCode: HttpStatus.NOT_FOUND,
}),
)
name: string,
): string {
return name;
}
返回结果如下:
我们试试自定义工厂函数:
@Get()
getHello(
@Query(
'name',
new ParseIntPipe({
exceptionFactory: (msg) => {
throw new HttpException('666啊' + msg, HttpStatus.NOT_ACCEPTABLE);
},
}),
)
name: string,
): string {
return name;
}
返回结果如下:
注意:errorHttpStatusCode 的类型是有限制的,只能是 ErrorHttpStatusCode
类型,也就是说你不能返回200等非 ErrorHttpStatusCode
类型的值。
其他内置管道验证与上述案例大同小异,我就不一一演示了,你们可以自己试试。
使用自定义管道验证
模拟项目真实使用场景:假设我们需要写一个创建用户的post接口,需要接受两个参数:name、age,要求name必须是3-6位的字符串,age必须是数字类型。
OK,需求创建完成,通常我们要自定义验证会使用 class-validator
这样一个工具包,里面有各种类型验证方法,方便我们,同时还需要下载 class-transformer
这样一个转换工具包,放心,下面我们就会用到。
下载两个工具包:
pnpm i --save class-validator class-transformer
接下来让我们一起实现下,首先我们在实际做项目中会创建一个dto文件,这里通常就是定义接口参数的地方, 同时也会验证参数的类型,如下我们创建一个create-user.dto.ts文件添加对应的验证装饰器:
解释下 @Length()
装饰器:
我们将鼠标移入 @Length()
上会发现要求我们必须传入最小值,最大值选填,还可以配置验证信息,validationOptions
我们传入message参数,自定义了校验提示语:
看一下 validationOptions
类型定义
接下来我们使用定义的 CreateUserDto
:
- 导入CreateUserDto
- 改为post请求
- 使用Body装饰器接受参数,并且配置管道验证
让我们来试下吧:
可以看到,管道验证成功了,并且自动将错误信息返回了,并且name字段的验证信息是我们在 @Length()
装饰器中定义的信息,第二条验证信息的意思是age字段不是number类型,那我们按照提示修改下:
我们按照规则修改了传入的参数,但是还是提示age字段的类型不正确,这是为什么呢?
原因就浏览器通常会把接口的参数默认都转成字符串,所以我们虽然传的是number类型,但是经过浏览器自动转换,被动变成了string类型,我们可以先把验证装饰器去掉来看下打印信息:
那这可怎么办呢?
还记得我们安装的 class-transformer
这个转换工具包吗?就用它来实现:
在dto中增加 @Type()
装饰器,用来指定参数属性类型,这里我们定义的是number,那么增加这个装饰器后,会自动转换为number类型,然后再去验证。
现在虽然增加了 @Type()
装饰器,但是还是不能实现的,因为 ValidationPipe
管道默认是不允许转换的,需要手动开启:
顺便来看下 ValidationPipe
管道定义的类型
OK,这样我们就实现了参数的类型转换,让我们再试一下:
看下打印结果:
正常项目中我们使用 @Type()
装饰器就够用了,如果转换方式比较复杂并且有复杂转换逻辑的话,也可以使用 @Transform()
装饰器,接收一个函数来自定义转换逻辑:
例如:
import { Transform, Type } from "class-transformer";
import { IsNumber, IsString, Length, } from "class-validator";
export class CreateUserDto {
@IsString()
@Length(3,6)
name: string
@IsNumber()
@Transform((value) => parseInt(value.value))
age:number
}
@Transform()
装饰器的作用与 @Type()
装饰器的作用是有区别的:
@Transform()
装饰器主要用于自定义转换逻辑,可以处理复杂的转换需求。@Type()
装饰器主要用于指定属性的类型,特别是在处理嵌套对象时。
OK,这就是项目中接口参数验证的真实案例demo,道友学废了吗?
觉得写的还行的话烦请多多关注、支持,将持续更新中💪~