文檔:https://docs.nestjs.cn/9/pipes
管道是什麼
管道是具有 @Injectable()
裝飾器的類。管道應實現 PipeTransform
接口。
管道的作用
管道有兩個典型的應用場景:
- 轉換:管道將輸入數據轉換爲所需的數據輸出(例如,將字符串轉換爲整數)
- 驗證:對輸入數據進行驗證,如果驗證成功繼續傳遞; 驗證失敗則拋出異常
內置管道
Nest
自帶九個開箱即用的管道,即
ValidationPipe
ParseIntPipe
ParseFloatPipe
ParseBoolPipe
ParseArrayPipe
ParseUUIDPipe
ParseEnumPipe
DefaultValuePipe
ParseFilePipe
他們從 @nestjs/common
包中導出
內置管道案例
創建 P 模塊
nest g resource p
案例1: string 轉 number
我們接受的路由參數希望是一個number 類型 現在是string
這時候可以用 ParseIntPipe
內置管道
例:
@Get(':id')
findOne(@Param('id', ParseIntPipe) id: number) {
console.log('id type===========>: ', typeof id);
return this.pService.findOne(+id);
}
案例2:驗證UUId
安裝uuid
npm install uuid -S
npm install @types/uuid -D
關鍵代碼
// uuid 用於後面正確的驗證
import * as uuid from 'uuid';
console.log(uuid.v4());
// 驗證uuid
@Get(':id')
findOne(@Param('id', ParseUUIDPipe) id: string) {
return this.pService.findOne(+id);
}
完整代碼
import { Controller, Get, Post, Body, Patch, Param, Delete, ParseUUIDPipe } from '@nestjs/common';
import { PService } from './p.service';
import { CreatePDto } from './dto/create-p.dto';
import { UpdatePDto } from './dto/update-p.dto';
// uuid 用於後面正確的驗證
import * as uuid from 'uuid';
console.log(uuid.v4());
@Controller('p')
export class PController {
constructor(private readonly pService: PService) {}
@Post()
create(@Body() createPDto: CreatePDto) {
return this.pService.create(createPDto);
}
@Get()
findAll() {
return this.pService.findAll();
}
// 驗證uuid
@Get(':id')
findOne(@Param('id', ParseUUIDPipe) id: string) {
return this.pService.findOne(+id);
}
@Patch(':id')
update(@Param('id') id: string, @Body() updatePDto: UpdatePDto) {
return this.pService.update(+id, updatePDto);
}
@Delete(':id')
remove(@Param('id') id: string) {
return this.pService.remove(+id);
}
}
測試
uuid 格式錯誤
效果如圖
uuid 格式正確
上面代碼裏面我們生成了一個uuid
7f145099-e9c7-47d9-99fb-a0a3f9a39bd7
正確的就通過了
管道驗證DTO
其實也叫類驗證器,文檔:
https://docs.nestjs.cn/9/pipes?id=類驗證器
官方內置的功能太少了,這時候可以使用類驗證器的方式使用第三方的
安裝
npm i --save class-validator class-transformer
文檔
https://github.com/typestack/class-validator
驗證修飾器
通用驗證裝飾器
修飾器 | 描述(英文) | 描述(中文) |
---|---|---|
@IsDefined(value: any) |
Checks if value is defined (!== undefined, !== null). This is the only decorator that ignores skipMissingProperties option. | 檢查是否定義了值 (!== undefined, !== null)。這是唯一忽略skipMissingProperties選項的裝飾程序 |
@IsOptional() |
Checks if given value is empty (=== null, === undefined) and if so, ignores all the validators on the property. | 檢查給定值是否爲空(=== null, === undefined) ,如果是,則忽略屬性上的所有驗證程序 |
@Equals(comparison: any) |
Checks if value equals ("===") comparison. | 檢查值是否相等(“===”)比較 |
@NotEquals(comparison: any) |
Checks if value not equal ("!==") comparison. | 檢查值是否不相等(“!==”)比較 |
@IsEmpty() |
Checks if given value is empty (=== ‘’, === null, === undefined). | 檢查給定值是否爲空(=== ‘’, === null, === undefined) |
@IsNotEmpty() |
Checks if given value is not empty (!== ‘’, !== null, !== undefined). | 檢查給定值是否不爲空 (!== ‘’, !== null, !== undefined) |
@IsIn(values: any[]) |
Checks if value is in a array of allowed values. | 檢查值是否在允許值的數組中 |
@IsNotIn(values: any[]) |
Checks if value is not in a array of disallowed values. | 檢查值是否不在不允許的值數組中 |
類型驗證裝飾器
修飾器 | 描述(英文) | 描述(中文) |
---|---|---|
@IsBoolean() |
Checks if a value is a boolean. | 是否爲布爾值 |
@IsDate() |
Checks if the value is a date. | 是否爲日期 |
@IsString() |
Checks if the string is a string. | 是否爲字符串 |
@IsNumber(options: IsNumberOptions) |
Checks if the value is a number. | 是否爲數字 |
@IsInt() |
Checks if the value is an integer number. | 是否爲整數 |
@IsArray() |
Checks if the value is an array | 是否爲數組 |
@IsEnum(entity: object) |
Checks if the value is an valid enum | 是否是有效的枚舉 |
Number validation decorators |
數字驗證裝飾器
修飾器 | 描述(英文) | 描述(中文) |
---|---|---|
@IsDivisibleBy(num: number) |
Checks if the value is a number that’s divisible by another. | 是否是可以被另一個數整除的數 |
@IsPositive() |
Checks if the value is a positive number greater than zero. | 是否是大於0的整數 |
@IsNegative() |
Checks if the value is a negative number smaller than zero. | 是否是小於0的整數 |
@Min(min: number) |
Checks if the given number is greater than or equal to given number. | 是否大於等於給定的數 |
@Max(max: number) |
Checks if the given number is less than or equal to given number. | 是否小於等於給定的數 |
日期驗證裝飾器
修飾器 | 描述(英文) | 描述(中文) |
---|---|---|
@MinDate(date: Date) |
Checks if the value is a date that’s after the specified date. | 是否在指定日期之後 |
@MaxDate(date: Date) |
Checks if the value is a date that’s before the specified date. | 是否在指定日期之前 |
字符串類型驗證裝飾器
修飾器 | 描述(英文) | 描述(中文) |
---|---|---|
@IsBooleanString() |
Checks if a string is a boolean (e.g. is “true” or “false”). | 是否爲布爾值(例如“true”或“false”) |
@IsDateString() |
Alias for @IsISO8601() . |
@IsISO8601()的別名 |
@IsNumberString(options?: IsNumericOptions) |
Checks if a string is a number. | 檢查字符串是否爲數字 |
字符串驗證裝飾器
修飾器 | 描述(英文) | 描述(中文) |
---|---|---|
@Contains(seed: string) |
Checks if the string contains the seed. | 是否包含種子 |
@NotContains(seed: string) |
Checks if the string not contains the seed. | 是否不包含種子 |
@IsAlpha() |
Checks if the string contains only letters (a-zA-Z). | 是否只包含字母 |
@IsAlphanumeric() |
Checks if the string contains only letters and numbers. | 是否只包含字母和數字 |
@IsDecimal(options?: IsDecimalOptions) |
Checks if the string is a valid decimal value. Default IsDecimalOptions are force_decimal=False , decimal_digits: '1,' , locale: 'en-US' |
是否爲有效的十進制值。默認的IsDecimalOptions是force_decimal=False,decimal_digits:‘1’,locale:‘en-US’ |
@IsAscii() |
Checks if the string contains ASCII chars only. | 是否只包含ASCII字符 |
@IsBase32() |
Checks if a string is base32 encoded. | 是否是base32編碼的 |
@IsBase64() |
Checks if a string is base64 encoded. | 是否是base64編碼的 |
@IsIBAN() |
Checks if a string is a IBAN (International Bank Account Number). | 是否爲IBAN(國際銀行帳號) |
@IsBIC() |
Checks if a string is a BIC (Bank Identification Code) or SWIFT code. | 是BIC(銀行識別碼)還是SWIFT碼 |
@IsByteLength(min: number, max?: number) |
Checks if the string’s length (in bytes) falls in a range. | 長度(以字節爲單位)是否在某個範圍內 |
@IsCreditCard() |
Checks if the string is a credit card. | 是否爲信用卡 |
@IsCurrency(options?: IsCurrencyOptions) |
Checks if the string is a valid currency amount. | 是否爲有效的貨幣金額 |
@IsEthereumAddress() |
Checks if the string is an Ethereum address using basic regex. Does not validate address checksums. | 是否是以太坊地址。不驗證地址校驗和 |
@IsBtcAddress() |
Checks if the string is a valid BTC address. | 是否爲有效的BTC地址 |
@IsDataURI() |
Checks if the string is a data uri format. | 是否爲數據uri格式 |
@IsEmail(options?: IsEmailOptions) |
Checks if the string is an email. | 是否爲電子郵件 |
@IsFQDN(options?: IsFQDNOptions) |
Checks if the string is a fully qualified domain name (e.g. domain.com). | 是否是完全限定的域名(例如domain.com) |
@IsFullWidth() |
Checks if the string contains any full-width chars. | 是否包含任何全角字符 |
@IsHalfWidth() |
Checks if the string contains any half-width chars. | 是否包含任何半角字符 |
@IsVariableWidth() |
Checks if the string contains a mixture of full and half-width chars. | 是否包含全半角字符 |
@IsHexColor() |
Checks if the string is a hexadecimal color. | 是否爲十六進制顏色 |
@IsHSLColor() |
Checks if the string is an HSL color based on CSS Colors Level 4 specification. | 是否是基於CSS Colors Level 4規範的HSL顏色 |
@IsRgbColor(options?: IsRgbOptions) |
Checks if the string is a rgb or rgba color. | 是rgb還是rgba顏色 |
@IsIdentityCard(locale?: string) |
Checks if the string is a valid identity card code. | 是否是有效的身份證代碼(估計是國外的身份證格式) |
@IsPassportNumber(countryCode?: string) |
Checks if the string is a valid passport number relative to a specific country code. | 是否是相對於特定國家代碼的有效護照號碼 |
@IsPostalCode(locale?: string) |
Checks if the string is a postal code. | 是否是郵政編碼 |
@IsHexadecimal() |
Checks if the string is a hexadecimal number. | 是否爲十六進制數 |
@IsOctal() |
Checks if the string is a octal number. | 是否爲八進制數 |
@IsMACAddress(options?: IsMACAddressOptions) |
Checks if the string is a MAC Address. | 是否爲MAC地址 |
@IsIP(version?: "4"|"6") |
Checks if the string is an IP (version 4 or 6). | 是否爲IP(版本4或6) |
@IsPort() |
Checks if the string is a valid port number. | 是否爲有效的端口號 |
@IsISBN(version?: "10"|"13") |
Checks if the string is an ISBN (version 10 or 13). | 是否爲ISBN(版本10或13) |
@IsEAN() |
Checks if the string is an if the string is an EAN (European Article Number). | 是否爲EAN(歐洲商品編號) |
@IsISIN() |
Checks if the string is an ISIN (stock/security identifier). | 是否爲ISIN(股票/安全標識符) |
@IsISO8601(options?: IsISO8601Options) |
Checks if the string is a valid ISO 8601 date format. Use the option strict = true for additional checks for a valid date. | 是否爲有效的ISO 8601日期格式。對於有效日期的其他檢查,請使用選項strict=true。 |
@IsJSON() |
Checks if the string is valid JSON. | 是否爲有效的JSON |
@IsJWT() |
Checks if the string is valid JWT. | 是否爲有效的JWT |
@IsObject() |
Checks if the object is valid Object (null, functions, arrays will return false). | 是否爲有效對象(null、函數、數組將返回false) |
@IsNotEmptyObject() |
Checks if the object is not empty. | 對象是否爲空 |
@IsLowercase() |
Checks if the string is lowercase. | 是否爲小寫 |
@IsLatLong() |
Checks if the string is a valid latitude-longitude coordinate in the format lat, long. | 是否爲lat,long格式的有效經緯度座標 |
@IsLatitude() |
Checks if the string or number is a valid latitude coordinate. | 檢查字符串或數字是否是有效的緯度座標 |
@IsLongitude() |
Checks if the string or number is a valid longitude coordinate. | 檢查字符串或數字是否爲有效的經度座標 |
@IsMobilePhone(locale: string) |
Checks if the string is a mobile phone number. | 是否是移動電話號碼 |
@IsISO31661Alpha2() |
Checks if the string is a valid ISO 3166-1 alpha-2 officially assigned country code. | 是否是有效的iso3166-1alpha-2官方指定的國家代碼。 |
@IsISO31661Alpha3() |
Checks if the string is a valid ISO 3166-1 alpha-3 officially assigned country code. | 是否是有效的iso3166-1alpha-3官方指定的國家代碼。 |
@IsLocale() |
Checks if the string is a locale. | 是否爲區域設置 |
@IsPhoneNumber(region: string) |
Checks if the string is a valid phone numberusing libphonenumber-js. | 是否是有效的電話號碼 |
@IsMongoId() |
Checks if the string is a valid hex-encoded representation of a MongoDB ObjectId. | 是否是MongoDB ObjectId的有效十六進制編碼表示形式 |
@IsMultibyte() |
Checks if the string contains one or more multibyte chars. | 是否包含一個或多個多字節字符 |
@IsNumberString(options?: IsNumericOptions) |
Checks if the string is numeric. | 是否包含任何代理項對字符 |
@IsSurrogatePair() |
Checks if the string contains any surrogate pairs chars. | 是否包含任何代理項對字符 |
@IsUrl(options?: IsURLOptions) |
Checks if the string is an url. | 是否爲url |
@IsMagnetURI() |
Checks if the string is a magnet uri format. | 是否爲magneturi格式 |
@IsUUID(version?: "3"|"4"|"5"|"all") |
Checks if the string is a UUID (version 3, 4, 5 or all ). | 是否是UUID(version 3、4、5或all) |
@IsFirebasePushId() |
Checks if the string is a Firebase Push ID | 是否爲Firebase Push ID |
@IsUppercase() |
Checks if the string is uppercase. | 是否爲大寫 |
@Length(min: number, max?: number) |
Checks if the string’s length falls in a range. | 符串的長度是否在某個範圍內 |
@MinLength(min: number) |
Checks if the string’s length is not less than given number. | 字符串的長度是否不小於給定的數字 |
@MaxLength(max: number) |
Checks if the string’s length is not more than given number. | 字符串的長度是否不大於給定的數字 |
@Matches(pattern: RegExp, modifiers?: string) |
Checks if string matches the pattern. Either matches(‘foo’, /foo/i) or matches(‘foo’, ‘foo’, ‘i’). | 是否與模式匹配,匹配(‘foo’,/foo/i)或匹配(‘foo’,‘foo’,‘i’) |
@IsMilitaryTime() |
Checks if the string is a valid representation of military time in the format HH:MM. | 是否是HH:MM格式的有效軍事時間表示形式 |
@IsHash(algorithm: string) |
Checks if the string is a hash The following types are supported:md4 , md5 , sha1 , sha256 , sha384 , sha512 , ripemd128 , ripemd160 , tiger128 , tiger160 , tiger192 , crc32 , crc32b . |
是否是散列,以下類型是supported:md4、md5、sha1、sha256、sha384、sha512、ripemd128、ripemd160、tiger128、tiger128、tiger192、crc32、crc32b。 |
@IsMimeType() |
Checks if the string matches to a valid MIME type format | 是否與有效的MIME類型格式匹配 |
@IsSemVer() |
Checks if the string is a Semantic Versioning Specification (SemVer). | 是否爲語義版本控制規範(SemVer) |
@IsISSN(options?: IsISSNOptions) |
Checks if the string is a ISSN. | 是否爲ISSN |
@IsISRC() |
Checks if the string is a ISRC. | 是否爲ISRC |
@IsRFC3339() |
Checks if the string is a valid RFC 3339 date. | 是否爲有效的RFC 3339日期 |
數組驗證裝飾器
修飾器 | 描述(英文) | 描述(中文) |
---|---|---|
@ArrayContains(values: any[]) |
Checks if array contains all values from the given array of values. | 是否包含給定值數組中的所有值 |
@ArrayNotContains(values: any[]) |
Checks if array does not contain any of the given values. | 是否不包含任何給定值 |
@ArrayNotEmpty() |
Checks if given array is not empty. | 是否爲空 |
@ArrayMinSize(min: number) |
Checks if the array’s length is greater than or equal to the specified number. | 數組的長度是否大於或等於指定的數字 |
@ArrayMaxSize(max: number) |
Checks if the array’s length is less or equal to the specified number. | 數組的長度是否小於或等於指定的數字 |
@ArrayUnique(identifier?: (o) => any) |
Checks if all array’s values are unique. Comparison for objects is reference-based. Optional function can be speciefied which return value will be used for the comparsion. | 所有數組的值是否唯一。對象的比較是基於引用的。可選函數可以指定用於比較的返回值 |
對象驗證裝飾器
修飾器 | 描述(英文) | 描述(中文) |
---|---|---|
@IsInstance(value: any) |
Checks if the property is an instance of the passed value. | 屬性是否是傳遞值的實例 |
其他驗證裝飾器
修飾器 | 描述(英文) | 描述(中文) |
---|---|---|
@Allow() |
Prevent stripping off the property when no other constraint is specified for it. | 防止在沒有爲屬性指定其他約束時剝離該屬性 |
管道驗證DTO 案例
創建一個管道
nest g pi 文件名字
例:
nest g pi p
創建DTO 驗證類
例:
import {IsNotEmpty,IsString} from 'class-validator'
export class CreatePDto {
@IsNotEmpty()//驗證是否爲空
@IsString() //是否爲字符串
name:string;
@IsNotEmpty()
age:number
}
在controller 使用管道 和 定義類型
關鍵代碼
// 類驗證器
@Post()
create(@Body(PPipe) createPDto: CreatePDto) {
return this.pService.create(createPDto);
}
完整代碼
import { Controller, Get, Post, Body, Patch, Param, Delete, ParseUUIDPipe } from '@nestjs/common';
import { PService } from './p.service';
import { CreatePDto } from './dto/create-p.dto';
import { UpdatePDto } from './dto/update-p.dto';
import { PPipe } from './p/p.pipe'
// uuid 用於後面正確的驗證
import * as uuid from 'uuid';
console.log(uuid.v4());
@Controller('p')
export class PController {
constructor(private readonly pService: PService) {}
// 類驗證器
@Post()
create(@Body(PPipe) createPDto: CreatePDto) {
return this.pService.create(createPDto);
}
@Get()
findAll() {
return this.pService.findAll();
}
// 驗證uuid
@Get(':id')
findOne(@Param('id', ParseUUIDPipe) id: string) {
return this.pService.findOne(+id);
}
@Patch(':id')
update(@Param('id') id: string, @Body() updatePDto: UpdatePDto) {
return this.pService.update(+id, updatePDto);
}
@Delete(':id')
remove(@Param('id') id: string) {
return this.pService.remove(+id);
}
}
實現驗證transform
import { ArgumentMetadata, HttpException, HttpStatus, Injectable, PipeTransform } from '@nestjs/common';
import { plainToInstance } from 'class-transformer';
import { validate } from 'class-validator';
@Injectable()
export class PPipe implements PipeTransform {
async transform(value: any, metadata: ArgumentMetadata) {
// value 就是 前端傳過來的數據
// metaData 就是元數據 通過 metatype 可以去實例化這個類
console.log(value, metadata);
// 實例化DTO
const DTO = plainToInstance(metadata.metatype, value);
// 通過 validate 驗證 DTO 返回一個promise 的錯誤信息
const errors = await validate(DTO);
// 如果有錯誤拋出
if(errors.length > 0){
throw new HttpException(errors, HttpStatus.BAD_REQUEST);
}
return value;
}
}
測試
格式錯誤
格式正確
註冊全局的DTO驗證管道
https://docs.nestjs.cn/9/pipes?id=全局管道
上面那個案例是我們根據官方文檔寫的,其實官方已經提供了一個寫好的
只不過我們使用自己的可以自定義,你也可以全局註冊自己的驗證管道
註冊
全局的一般在main.ts
中註冊
例:
import { NestFactory } from '@nestjs/core';
import { AppModule } from './app.module';
import { ValidationPipe } from '@nestjs/common';
async function bootstrap() {
const app = await NestFactory.create(AppModule);
// 註冊全局管道
app.useGlobalPipes(new ValidationPipe());
await app.listen(3000);
}
bootstrap();
使用
上面那個例子,我們使用的是自定義的,這次使用全局的
全局是默認的,所以不用特意寫