Nest.js参数校验和自定义返回数据格式详解
0x0 参数校验
参数校验大部分业务是使用 Nest.js 中的管道 方法实现,具体可以查阅文档 。不过编写过程中遇到一些问题,虽然文档讲得比较晦涩。
在做个查询接口,里面包含一些参数,做成 dto 结构数据:
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 进行转换:
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 选项:
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 }) } ] })
俩者使用方法区别于程序的是否混合应用类型。
我这边为了省事直接写在全局方法里,最终到 service 拿到的数据就是经过管道业务处理过的数据,不需要在 service 层进行大量的数据类型判断。
0x1 自定义返回数据格式
在 controller 返回的数据都是从数据库表结构而来:
{ "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" }
如果需要定义最终返回接口的数据格式例如:
{ "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" } }
这里就需要做个自定义成功请求拦截器:
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 最好放在第一个,否则会失效。
错误过滤器:
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 隐藏实体类中的某个字段
本来想使用 @Exclude 属性来隐藏数据库中一些敏感的字段,但发现无法满足特殊的需求,如果是返回单条实例可以实现隐藏,但是我有个 findAll 就无法实现了,上面在 Serialization | NestJS - A progressive Node.js framework 文档里说的非常详细,不过这里还有个办法。首先在实力类敏感数据字段上添加属性:
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 登录查询中:
const user = await getRepository(UserEntity) .createQueryBuilder('user') .where('user.username = :username', { username }) .addSelect('user.password') .getOne()
.addSelect('user.password') 添加这个属性查询将会包括 password 这个字段,否则普通查询的方法不会包括这个字段。
总结
到此这篇关于Nest.js参数校验和自定义返回数据格式的文章就介绍到这了,更多相关Nest.js参数校验和数据格式内容请搜索猪先飞以前的文章或继续浏览下面的相关文章希望大家以后多多支持猪先飞!
相关文章
- 这篇文章主要给大家介绍了关于Nest.js参数校验和自定义返回数据格式的相关资料,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧...2021-03-28
校验非空的注解@NotNull如何取得自定义的message
这篇文章主要介绍了校验非空的注解@NotNull如何取得自定义的message,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教...2021-09-29- 这篇文章主要介绍了解决Springboot get请求是参数过长的情况,具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧...2020-09-17
PHP中empty和isset对于参数结构的判断及empty()和isset()的区别
废话不多说了,直接给大家贴代码了。<?php class test{} $a1 = null; $a2 = ""; //$a3 = $a4 = 0; $a5 = '0'; $a6 = false; $a7 = array(); //var $a8; $a9 = new test(); for ($i=1; $i <=9 ; $i++) {...2015-11-24- 这篇文章主要介绍了java正则表达式判断前端参数修改表中另一个字段的值,需要的朋友可以参考下...2021-05-07
- mysql安装成功后有几个默认的配置模板,列表如下: my-huge.cnf : 用于高端产品服务器,包括1到2GB RAM,主要运行mysql my-innodb-heavy-4G.ini : 用于只有innodb的安装,最多有4GB RAM,支持大的查询和低流量 my-large.cnf : 用于...2015-03-15
- 这篇文章主要给大家介绍了关于C#中out参数、ref参数与值参数的用法及区别的相关资料,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧...2020-06-25
- 这篇文章主要介绍了C#泛型的类型参数约束的相关资料,文中讲解非常细致,帮助大家更好的理解和学习c#,感兴趣的朋友可以了解下...2020-07-31
- 这篇文章主要介绍了Nest.js 授权验证的方法示例,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧...2021-02-22
- 这篇文章主要介绍了Java线程池中的各个参数如何合理设置操作,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教...2021-06-19
- 这篇文章主要介绍了vue+axios全局添加请求头和参数操作,具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧...2020-07-24
- 这篇文章主要介绍了SpringBoot接口接收json参数解析,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教...2021-10-19
处理@PathVariable注解允许参数为空、允许不传参数的问题
这篇文章主要介绍了处理@PathVariable注解允许参数为空、允许不传参数的问题,具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧...2021-02-23- 这篇文章主要介绍了pytorch 实现冻结部分参数训练另一部分,具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧...2021-03-27
- 这篇文章主要介绍了详解Java后端优雅验证参数合法性,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧...2021-02-18
详解element-ui 表单校验 Rules 配置 常用黑科技
这篇文章主要介绍了element-ui 表单校验 Rules 配置 常用黑科技,本文通过实例代码给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下...2020-07-11- 这篇文章主要介绍了C#向线程中传递多个参数的解决方法(两种)的相关资料,非常不错,具有参考借鉴价值,需要的朋友可以参考下...2020-06-25
- 这篇文章主要给大家介绍了关于Nest.js环境变量配置与序列化的相关资料,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧...2021-02-21
- 这篇文章主要介绍了spring cloud gateway中如何读取请求参数的操作,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教...2021-07-15
- 这篇文章主要介绍了使用JavaScript获取URL中的参数(两种方法)的相关资料,非常不错,具有参考借鉴价值,需要的朋友可以参考下...2016-11-22