Nest.js參數(shù)校驗(yàn)和自定義返回?cái)?shù)據(jù)格式詳解
0x0 參數(shù)校驗(yàn)
參數(shù)校驗(yàn)大部分業(yè)務(wù)是使用 Nest.js 中的管道 方法實(shí)現(xiàn),具體可以查閱文檔 。不過編寫過程中遇到一些問題,雖然文檔講得比較晦澀。
在做個(gè)查詢接口,里面包含一些參數(shù),做成 dto 結(jié)構(gòu)數(shù)據(jù):
import { ApiProperty } from '@nestjs/swagger'
export class QueryUserDto {
@ApiProperty({
required: false,
description: '頁碼'
})
readonly currentPage: number
@ApiProperty({
required: false,
description: '條數(shù)'
})
readonly pageSize: number
@ApiProperty({
required: false,
description: '用戶賬號'
})
readonly username?: string
@ApiProperty({
required: false,
description: '用戶狀態(tài)'
})
readonly activeStatus: number
@ApiProperty({
required: false,
description: '排序的方式: ASC, DESC'
})
readonly order: 'DESC' | 'ASC'
}
TYPESCRIPT
在 @Query 請求傳入對應(yīng)的參數(shù),發(fā)現(xiàn)得到的數(shù)據(jù)類型都是 String ,然后查閱相關(guān)文檔才明白還需要 class-transformer 的 Type 進(jìn)行轉(zhuǎn)換:
import { ApiProperty } from '@nestjs/swagger'
import { Type } from 'class-transformer'
export class QueryUserDto {
@ApiProperty({
required: false,
description: '頁碼'
})
@Type(() => Number)
readonly currentPage: number = 1
@ApiProperty({
required: false,
description: '條數(shù)'
})
@Type(() => Number)
readonly pageSize: number = 10
@ApiProperty({
required: false,
description: '用戶賬號'
})
readonly username?: string
@ApiProperty({
required: false,
description: '用戶狀態(tài)'
})
@Type(() => Number)
readonly activeStatus: number = 3
@ApiProperty({
required: false,
description: '排序的方式: ASC, DESC'
})
readonly order: 'DESC' | 'ASC' = 'DESC'
}
然后在 ValidationPipe 管道方法里開啟 transform 選項(xiàng):
app.useGlobalPipes(
new ValidationPipe({
transform: true
})
)
或者在 app.modules.ts 注入:
import { ValidationPipe } from '@nestjs/common'
import { APP_PIPE } from '@nestjs/core'
@Module({
imports: [
// ...
],
controllers: [AppController],
providers: [
{
provide: APP_PIPE,
useValue: new ValidationPipe({
transform: true
})
}
]
})
倆者使用方法區(qū)別于程序的是否混合應(yīng)用類型。
我這邊為了省事直接寫在全局方法里,最終到 service 拿到的數(shù)據(jù)就是經(jīng)過管道業(yè)務(wù)處理過的數(shù)據(jù),不需要在 service 層進(jìn)行大量的數(shù)據(jù)類型判斷。
0x1 自定義返回?cái)?shù)據(jù)格式
在 controller 返回的數(shù)據(jù)都是從數(shù)據(jù)庫表結(jié)構(gòu)而來:
{
"id": "d8d5a56c-ee9f-4e41-be48-5414a7a5712c",
"username": "Akeem.Cremin",
"password": "$2b$10$kRcsmN6ewFC2GOs0TEg6TuvDbNzf1VGCbQf2fI1UeyPAiZCq9rMKm",
"email": "Garrett87@hotmail.com",
"nickname": "Wallace Nicolas",
"role": "user",
"isActive": true,
"createdTime": "2021-03-24T15:24:26.806Z",
"updatedTime": "2021-03-24T15:24:26.806Z"
}
如果需要定義最終返回接口的數(shù)據(jù)格式例如:
{
"statusCode": 200,
"message": "獲取成功",
"data": {
"id": "d8d5a56c-ee9f-4e41-be48-5414a7a5712c",
"username": "Akeem.Cremin",
"password": "$2b$10$kRcsmN6ewFC2GOs0TEg6TuvDbNzf1VGCbQf2fI1UeyPAiZCq9rMKm",
"email": "Garrett87@hotmail.com",
"nickname": "Wallace Nicolas",
"role": "user",
"isActive": true,
"createdTime": "2021-03-24T15:24:26.806Z",
"updatedTime": "2021-03-24T15:24:26.806Z"
}
}
這里就需要做個(gè)自定義成功請求攔截器:
nest g in shared/interceptor/transform
import { CallHandler, ExecutionContext, Injectable, Logger, NestInterceptor } from '@nestjs/common'
import { Observable } from 'rxjs'
import { map } from 'rxjs/operators'
import { Request } from 'express'
interface Response<T> {
data: T
}
@Injectable()
export class TransformInterceptor<T> implements NestInterceptor<T, Response<T>> {
intercept(context: ExecutionContext, next: CallHandler<T>): Observable<any> {
const request = context.switchToHttp().getRequest<Request>()
Logger.log(request.url, '正常接口請求')
return next.handle().pipe(
map(data => {
return {
data: data,
statusCode: 200,
message: '請求成功'
}
})
)
}
}
然后在 app.module.ts 引入即可使用:
import { ValidationPipe } from '@nestjs/common'
import { APP_INTERCEPTOR } from '@nestjs/core'
import { TransformInterceptor } from '@/shared/interceptor/transform.interceptor'
@Module({
imports: [
// ...
],
controllers: [AppController],
providers: [
{
provide: APP_INTERCEPTOR,
useClass: TransformInterceptor
}
]
})
不過 APP_INTERCEPTOR 排序要注意,TransformInterceptor 最好放在第一個(gè),否則會失效。
錯誤過濾器:
nest g f shared/filters/httpException
import { ArgumentsHost, Catch, ExceptionFilter, HttpException, Logger } from '@nestjs/common'
import { Response, Request } from 'express'
@Catch(HttpException)
export class HttpExceptionFilter implements ExceptionFilter {
catch(exception: HttpException, host: ArgumentsHost) {
const context = host.switchToHttp()
const response = context.getResponse<Response>()
const request = context.getRequest<Request>()
const status = exception.getStatus()
const message = exception.message
Logger.log(`${request.url} - ${message}`, '非正常接口請求')
response.status(status).json({
statusCode: status,
message: message,
path: request.url,
timestamp: new Date().toISOString()
})
}
}
然后在 app.module.ts 引入即可使用:
import { ValidationPipe } from '@nestjs/common'
import { APP_FILTER } from '@nestjs/core'
import { HttpExceptionFilter } from '@/shared/filters/http-exception.filter'
@Module({
imports: [
// ...
],
controllers: [AppController],
providers: [
{
provide: APP_FILTER,
useClass: HttpExceptionFilter
}
]
})
0x2 隱藏實(shí)體類中的某個(gè)字段
本來想使用 @Exclude 屬性來隱藏?cái)?shù)據(jù)庫中一些敏感的字段,但發(fā)現(xiàn)無法滿足特殊的需求,如果是返回單條實(shí)例可以實(shí)現(xiàn)隱藏,但是我有個(gè) findAll 就無法實(shí)現(xiàn)了,上面在 Serialization | NestJS - A progressive Node.js framework 文檔里說的非常詳細(xì),不過這里還有個(gè)辦法。首先在實(shí)力類敏感數(shù)據(jù)字段上添加屬性:
import { BaseEntity, Entity, Column, PrimaryGeneratedColumn } from 'typeorm'
@Entity('user')
export class UserEntity extends BaseEntity {
@PrimaryGeneratedColumn('uuid', {
comment: '用戶編號'
})
id: string
@Column({
type: 'varchar',
length: 50,
unique: true,
comment: '登錄用戶'
})
username: string
@Column({
type: 'varchar',
length: 200,
select: false,
comment: '密碼'
})
password: string
select: false 可以在返回查詢結(jié)果隱藏這個(gè)字段,但所有涉及到這個(gè)字段查詢必須添加這個(gè)字段,比如我在 user.service.ts 登錄查詢中:
const user = await getRepository(UserEntity)
.createQueryBuilder('user')
.where('user.username = :username', { username })
.addSelect('user.password')
.getOne()
.addSelect('user.password') 添加這個(gè)屬性查詢將會包括 password 這個(gè)字段,否則普通查詢的方法不會包括這個(gè)字段。
總結(jié)
到此這篇關(guān)于Nest.js參數(shù)校驗(yàn)和自定義返回?cái)?shù)據(jù)格式的文章就介紹到這了,更多相關(guān)Nest.js參數(shù)校驗(yàn)和數(shù)據(jù)格式內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
詳解nodejs微信公眾號開發(fā)——4.自動回復(fù)各種消息
這篇文章主要介紹了詳解nodejs微信公眾號開發(fā)——4.自動回復(fù)各種消息,非常具有實(shí)用價(jià)值,需要的朋友可以參考下2017-04-04
node版本與node-sass版本不兼容時(shí)的問題及解決
這篇文章主要介紹了node版本與node-sass版本不兼容時(shí)的問題及解決方案,具有很好的參考價(jià)值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教2023-04-04
Node如何實(shí)現(xiàn)在瀏覽器預(yù)覽項(xiàng)目的所有圖片詳解
最近項(xiàng)目遇到了個(gè)需求,需要將存放圖片進(jìn)行預(yù)覽,所以這篇文章主要給大家介紹了關(guān)于Node如何實(shí)現(xiàn)在瀏覽器預(yù)覽項(xiàng)目的所有圖片的相關(guān)資料,文中通過實(shí)例代碼介紹的非常詳細(xì),需要的朋友可以參考下2023-01-01
no-vnc和node.js實(shí)現(xiàn)web遠(yuǎn)程桌面的完整步驟
這篇文章主要給大家介紹了關(guān)于no-vnc和node.js實(shí)現(xiàn)web遠(yuǎn)程桌面的完整步驟,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面來一起學(xué)習(xí)學(xué)習(xí)吧2019-08-08
使用Node.js實(shí)現(xiàn)簡易MVC框架的方法
下面小編就為大家?guī)硪黄褂肗ode.js實(shí)現(xiàn)簡易MVC框架的方法。小編覺得挺不錯的,現(xiàn)在就分享給大家,也給大家做個(gè)參考。一起跟隨小編過來看看吧2017-08-08
nodejs連接mysql數(shù)據(jù)庫及基本知識點(diǎn)詳解
這篇文章主要介紹了nodejs連接mysql數(shù)據(jù)庫,結(jié)合實(shí)例形式總結(jié)分析了nodejs連接與操作mysql數(shù)據(jù)庫的相關(guān)模板、配置及mysql數(shù)據(jù)庫查詢、添加數(shù)據(jù)等操作技巧,需要的朋友可以參考下2018-03-03

