神光《Nest 通关秘籍》学习总结-9种常见的Pipe参数校验方式
最近在学习神光大神的《Nest通关秘籍》,该小册主要包含下面这些内容:
想购买的可以点击《传送门》。
接下来的日子里,我将更新一系列的学习笔记。感兴趣的可以关注我的专栏《Nest 通关秘籍》学习总结。
特别申明:本系列文章已经经过作者本人的允许。 大家也不要想着白嫖,我的笔记只是个人边学习边记录的,不是很完整,大家想要深入学习还是要自己去购买原版小册。
本章我们来学习如何通过nest中的Pipe来对参数进行校验。
Pipe 是在参数传给 handler 之前对参数做一些验证和转换的 class。
内置的 Pipe 有这些:
- ValidationPipe
- ParseIntPipe
- ParseBoolPipe
- ParseArrayPipe
- ParseUUIDPipe
- DefaultValuePipe
- ParseEnumPipe
- ParseFloatPipe
- ParseFilePipe
它们都实现了 PipeTransform 接口:
1. ParseIntPipe
import { Controller, Get, ParseIntPipe, Query } from '@nestjs/common';
import { AppService } from './app.service';
@Controller()
export class AppController {
constructor(private readonly appService: AppService) {}
@Get()
getHello(@Query('a', ParseIntPipe) aa): string {
return aa + 1;
}
}
当我们传入的参数是int类型的时候,会正常返回,如果不是,会报错:
这里我们还可以指定错误状态码:
import {
Controller,
Get,
HttpStatus,
ParseIntPipe,
Query,
} from '@nestjs/common';
import { AppService } from './app.service';
@Controller()
export class AppController {
constructor(private readonly appService: AppService) {}
@Get()
getHello(
@Query(
'a',
new ParseIntPipe({
errorHttpStatusCode: HttpStatus.NOT_FOUND,
}),
)
a,
): string {
return a + 1;
}
}
注意:需要new ParseIntPipe()
返回的错误码就会变成404了。
还可以抛一个异常出来,然后让 exception filter 处理:
import {
Controller,
Get,
HttpException,
HttpStatus,
ParseIntPipe,
Query,
} from '@nestjs/common';
import { AppService } from './app.service';
@Controller()
export class AppController {
constructor(private readonly appService: AppService) {}
@Get()
getHello(
@Query(
'a',
new ParseIntPipe({
exceptionFactory: (msg) => {
console.log(msg);
throw new HttpException('xxx' + msg, HttpStatus.NOT_FOUND);
},
}),
)
a,
): string {
return a + 1;
}
}
可以看到,状态码和 message 都改了:
也可以加个 @UseFilters 来使用自己的 exception filter 处理.
2. ParseFloatPipe
@Get('b')
getB(
@Query('b', new ParseFloatPipe())
a,
): string {
return a + 1;
}
3. ParseBoolPipe
@Get('c')
getC(
@Query('a', new ParseBoolPipe())
a,
): string {
return typeof a;
}
4. ParseArrayPipe
安装两个包:
pnpm install -D class-validator class-transformer
- class-validator:用装饰器和非装饰器两种方式对 class 属性做验证的库
- class-transformer:把普通对象转换为对应的 class 实例的包
@Get('d')
getD(
@Query('a', new ParseArrayPipe({}))
a: Array<number>,
) {
return a.reduce((total, item) => total + item, 0);
}
发现它并没有转化成Number类型,所以返回了0123
。
这时候就需要用 new XxxPipe 的方式传入参数了:
@Get('d')
getD(
@Query(
'a',
new ParseArrayPipe({
items: Number,
}),
)
a: Array<number>,
) {
return a.reduce((total, item) => total + item, 0);
}
这时候就能得到正确的结果了:
此外,你还可以指定分隔符:
@Get('f')
getF(
@Query(
'a',
new ParseArrayPipe({
separator: '..',
}),
)
a: Array<string>,
) {
return a;
}
如果不传参的时候会报错,可以设置为optional
@Get('f')
getF(
@Query(
'a',
new ParseArrayPipe({
separator: '..',
optional: true,
}),
)
a: Array<string>,
) {
return a;
}
5. ParseEnumPipe
ParseEnumPipe
的使用场景是这样的:
限制参数的取值范围
先定义一个路径的枚举类型:
enum PATHENUM {
AAA = '111',
BBB = '222',
CCC = '333',
}
@Get('g/:enum')
getG(
@Param('enum', new ParseEnumPipe(PATHENUM))
e: PATHENUM,
) {
return e;
}
当我们访问PATHENUM
中的值的时候正常返回,如果我们访问一个http://127.0.0.1:3000/g/444,就会报下面的错误:
6. ParseUUIDPipe
UUID 是一种随机生成的几乎不可能重复的字符串,可以用来做 id。
我们先来生成一个UUID
// eslint-disable-next-line @typescript-eslint/no-var-requires
const uuid = require('uuid');
console.log(uuid.v4());
这样会生成一个v4的uuid
然后我们使用ParseUUIDPipe来校验一下:
@Get('h/:uuid')
getH(
@Param('uuid', new ParseUUIDPipe())
uuid: string,
) {
return uuid;
}
如果是错误的UUID,会报错:
7. DefaultValuePipe
这个是设置参数默认值的,当你没传参数的时候,会使用默认值:
@Get('i')
getI(
@Query('iii', new DefaultValuePipe('123'))
iii: string,
) {
return iii;
}
无参数:
有参数:
以上都是Get
参数。如果用POST
参数,阁下应该如何应对?
8. ValidationPipe
post 请求的数据是通过 @Body 装饰器来取,并且要有一个 dto class 来接收,
export class CreateAaaDto {
name: string;
}
import {
Controller,
Post,
} from '@nestjs/common';
import { AaaService } from './aaa.service';
import { CreateAaaDto } from './dto/create-aaa.dto';
@Controller('aaa')
export class AaaController {
constructor(private readonly aaaService: AaaService) {}
@Post()
create(@Body() createAaaDto: CreateAaaDto) {
console.log(createAaaDto);
}
}
可以看到正常接收到了参数。当我们在Body中接受的参数类型各种各样的时候,就需要对这些参数进行验证,也就是Validationpipe
。
它需要依赖下面两个包:
pnpm install -D class-validator class-transformer
然后在 @Body 里添加这个Validationpipe
:
import {
Controller,
Get,
Post,
Body,
Patch,
Param,
Delete,
ValidationPipe,
} from '@nestjs/common';
import { AaaService } from './aaa.service';
import { CreateAaaDto } from './dto/create-aaa.dto';
@Controller('aaa')
export class AaaController {
constructor(private readonly aaaService: AaaService) {}
@Post()
create(@Body(new ValidationPipe()) createAaaDto: CreateAaaDto) {
console.log(createAaaDto);
}
}
在 dto 这里,用 class-validator 包的 @IsInt 装饰器标记一下:
import { IsInt } from 'class-validator';
export class CreateAaaDto {
name: string;
@IsInt()
age: number;
}
现在当我们把age的参数传成非number类型的,就会报错了:
如果传成正确的类型,就会正常返回了:
class-validator 都支持的验证方式:
import { Contains, IsDate, IsEmail, IsFQDN, IsInt, Length, Max, Min } from 'class-validator';
export class Ppp {
@Length(10, 20)
title: string;
@Contains('hello')
text: string;
@IsInt()
@Min(0)
@Max(10)
rating: number;
@IsEmail()
email: string;
@IsFQDN()
site: string;
}
大家可以自己去一一验证。
9. ParseFilePipe
未完待续。。。
转载自:https://juejin.cn/post/7243725249590378551