管道

管道可以做两件事:

  1. 转换,将前端传入的数据转成成需要的数据
  2. 验证,类似于前端的rules配置验证规则

管道转换

Nestjs提供了八个内置转换API

  • ValidationPipe
  • ParseIntPipe
  • ParseFloatPipe
  • ParseBoolPipe
  • ParseArrayPipe
  • ParseUUIDPipe
  • ParseEnumPipe
  • DefaultValuePipe

可以根据需要将前端传来的数据转换成合适的类型

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
import {
Controller,
Get,
Param,
ParseIntPipe,
} from '@nestjs/common';
import { PService } from './p.service';
import { CreatePDto } from './dto/create-p.dto';
import { UpdatePDto } from './dto/update-p.dto';

@Controller('p')
export class PController {
constructor(private readonly pService: PService) {}

@Get(':id')
// 有时后台想接收number数据而不是string,此时可以用管道转换
findOne(@Param('id', ParseIntPipe) id: number) {
console.log(typeof id); // ->number,默认时应该是string
return this.pService.findOne(+id);
}
}

管道验证DTO

使用nest g res [实体名]创建一套crud模板时,nest会默认创建好该实体的DTO文件,它可以用于约束实体

1
export class CreateLoginDto {}

使用nest g pi [实体名]可以创建该实体的pipe文件

1
2
3
4
5
6
7
8
9
import { ArgumentMetadata, Injectable, PipeTransform } from '@nestjs/common';

@Injectable()
export class LoginPipe implements PipeTransform {
// value:前台传的数据 metadata:元数据,包括参数类型、装饰器类型、装饰器的值
transform(value: any, metadata: ArgumentMetadata) {
return value;
}
}

安装验证器:

1
npm i --save class-validator class-transformer

在DTO中定义数据的约束:

1
2
3
4
5
6
7
8
9
10
11
12
import { IsNotEmpty, IsString, Length, IsNumber } from 'class-validator';

export class CreateLoginDto {
@IsNotEmpty()
@IsString()
@Length(5, 10, {
message: '字数越界',
})
name: string;
@IsNumber()
age: number;
}

在pipe中验证数据:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
import {
ArgumentMetadata,
HttpException,
HttpStatus,
Injectable,
PipeTransform,
} from '@nestjs/common';
import { plainToInstance } from 'class-transformer';
import { validate } from 'class-validator';

@Injectable()
export class LoginPipe implements PipeTransform {
async transform(value: any, metadata: ArgumentMetadata) {
// plainToInstance会将值反射到DTO上
const DTO = plainToInstance(metadata.metatype, value);
// 验证数据,异步操作,如果有错误,会把所有错误以数组形式返回
const errors = await validate(DTO);
console.log(errors);
// 如果有错误,抛出
if (errors.length) {
throw new HttpException(errors, HttpStatus.BAD_REQUEST);
}
return value;
}
}

在controller中应用验证:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
import {
Controller,
Post,
Body,
} from '@nestjs/common';
import { LoginService } from './login.service';
import { CreateLoginDto } from './dto/create-login.dto';
import { UpdateLoginDto } from './dto/update-login.dto';
import { LoginPipe } from './login.pipe';

@Controller('login')
export class LoginController {
constructor(private readonly loginService: LoginService) {}

@Post()
// 管道直接塞进装饰器里就能用
create(@Body(LoginPipe) createLoginDto: CreateLoginDto) {
return this.loginService.create(createLoginDto);
}
}

nest为了用户方便,提供了简便应用数据验证的方式,就是使用nest提供的验证api在main.ts里全局注册:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
import { NestFactory } from '@nestjs/core';
import { VersioningType } from '@nestjs/common';
import { AppModule } from './app.module';
import { NestExpressApplication } from '@nestjs/platform-express';
import { ValidationPipe } from '@nestjs/common';

async function bootstrap() {
const app = await NestFactory.create<NestExpressApplication>(AppModule, {
cors: true,
});
app.enableVersioning({
type: VersioningType.URI,
});
// 应用数据约束检测,这样也不用在controller的装饰器里塞管道了
app.useGlobalPipes(new ValidationPipe());
await app.listen(3000);
}
bootstrap();