0x0 參數校驗
參數校驗大部分業務是使用 Nest.js 中的管道 方法實現,具體可以查閱文檔 。不過編寫過程中遇到一些問題,雖然文檔講得比較晦澀。
在做個查詢接口,里面包含一些參數,做成 dto 結構數據:
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
27
28
29
30
31
32
33
34
|
import { ApiProperty } from '@nestjs/swagger' export class QueryUserDto { @ApiProperty({ required: false , description: '頁碼' }) readonly currentPage: number @ApiProperty({ required: false , description: '條數' }) readonly pageSize: number @ApiProperty({ required: false , description: '用戶賬號' }) readonly username?: string @ApiProperty({ required: false , description: '用戶狀態' }) readonly activeStatus: number @ApiProperty({ required: false , description: '排序的方式: ASC, DESC' }) readonly order: 'DESC' | 'ASC' } TYPESCRIPT |
在 @Query 請求傳入對應的參數,發現得到的數據類型都是 String ,然后查閱相關文檔才明白還需要 class-transformer 的 Type 進行轉換:
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
27
28
29
30
31
32
33
34
35
36
37
|
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: '條數' }) @Type(() => Number) readonly pageSize: number = 10 @ApiProperty({ required: false , description: '用戶賬號' }) readonly username?: string @ApiProperty({ required: false , description: '用戶狀態' }) @Type(() => Number) readonly activeStatus: number = 3 @ApiProperty({ required: false , description: '排序的方式: ASC, DESC' }) readonly order: 'DESC' | 'ASC' = 'DESC' } |
然后在 ValidationPipe 管道方法里開啟 transform 選項:
1
2
3
4
5
|
app.useGlobalPipes( new ValidationPipe({ transform: true }) ) |
或者在 app.modules.ts 注入:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
|
import { ValidationPipe } from '@nestjs/common' import { APP_PIPE } from '@nestjs/core' @Module({ imports: [ // ... ], controllers: [AppController], providers: [ { provide: APP_PIPE, useValue: new ValidationPipe({ transform: true }) } ] }) |
倆者使用方法區別于程序的是否混合應用類型。
我這邊為了省事直接寫在全局方法里,最終到 service 拿到的數據就是經過管道業務處理過的數據,不需要在 service 層進行大量的數據類型判斷。
0x1 自定義返回數據格式
在 controller 返回的數據都是從數據庫表結構而來:
1
2
3
4
5
6
7
8
9
10
11
|
{ "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" } |
如果需要定義最終返回接口的數據格式例如:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
|
{ "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" } } |
這里就需要做個自定義成功請求攔截器:
1
|
nest g in shared/interceptor/transform |
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 { 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 引入即可使用:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
|
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 最好放在第一個,否則會失效。
錯誤過濾器:
1
|
nest g f shared /filters/httpException |
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
|
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 引入即可使用:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
|
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 隱藏實體類中的某個字段
本來想使用 @Exclude 屬性來隱藏數據庫中一些敏感的字段,但發現無法滿足特殊的需求,如果是返回單條實例可以實現隱藏,但是我有個 findAll 就無法實現了,上面在 Serialization | NestJS - A progressive Node.js framework 文檔里說的非常詳細,不過這里還有個辦法。首先在實力類敏感數據字段上添加屬性:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
|
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 可以在返回查詢結果隱藏這個字段,但所有涉及到這個字段查詢必須添加這個字段,比如我在 user.service.ts 登錄查詢中:
1
2
3
4
5
|
const user = await getRepository(UserEntity) .createQueryBuilder( 'user' ) .where( 'user.username = :username' , { username }) .addSelect( 'user.password' ) .getOne() |
.addSelect('user.password') 添加這個屬性查詢將會包括 password 這個字段,否則普通查詢的方法不會包括這個字段。
總結
到此這篇關于Nest.js參數校驗和自定義返回數據格式的文章就介紹到這了,更多相關Nest.js參數校驗和數據格式內容請搜索服務器之家以前的文章或繼續瀏覽下面的相關文章希望大家以后多多支持服務器之家!
原文鏈接:https://iiong.com/nest-js-parameter-check-and-custom-return-data-format/