Nest.js参数校验和自定义返回数据格式详解

 更新时间:2021年03月28日 11:55:14   作者:Jaxson Wang  
这篇文章主要给大家介绍了关于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参数校验和数据格式内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

相关文章

  • Node.js连接MySQL数据库的操作步骤

    Node.js连接MySQL数据库的操作步骤

    在现代 Web 开发中,与数据库的交互是不可避免的一部分,Node.js提供了许多库和模块,使得连接和操作 MySQL 数据库变得相对简单,本文将介绍如何使用Node.js连接MySQL数据库,并进行一些基本的操作,文中通过代码示例介绍的非常详细,需要的朋友可以参考下
    2023-11-11
  • 详解npm和cnpm混用的坑

    详解npm和cnpm混用的坑

    有没有遇到过npm和cnpm一起用的时候出现奇奇怪怪的问题呢? 有没有遇到过cnpm在支付宝小程序上面安装包无效?本文就详解一下npm和cnpm混用的坑,感兴趣的可以了解下
    2021-07-07
  • nodejs+axios爬取html出现中文乱码并解决示例

    nodejs+axios爬取html出现中文乱码并解决示例

    这篇文章主要为大家介绍了nodejs+axios爬取html出现中文乱码示例详解,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步,早日升职加薪
    2022-06-06
  • mac下的nodejs环境安装的步骤

    mac下的nodejs环境安装的步骤

    本篇文章主要介绍了mac下的nodejs环境安装的步骤,小编觉得挺不错的,现在分享给大家,也给大家做个参考。一起跟随小编过来看看吧
    2017-05-05
  • 如何在Express4.x中愉快地使用async的方法

    如何在Express4.x中愉快地使用async的方法

    这篇文章主要介绍了如何在Express4.x中愉快地使用async的方法,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2020-11-11
  • 手把手带你搭建一个node cli的方法示例

    手把手带你搭建一个node cli的方法示例

    这篇文章主要介绍了手把手带你搭建一个node cli的方法示例,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2020-08-08
  • node中npm ERR! network ‘proxy‘ 配置问题解决

    node中npm ERR! network ‘proxy‘ 配置问题解决

    在进行npm依赖管理时,可能会遇到因网络配置不当导致的错误,如npm ERR! network proxy config is set properly,下面就来介绍一下,感兴趣的可以了解一下
    2024-09-09
  • 利用Decorator如何控制Koa路由详解

    利用Decorator如何控制Koa路由详解

    最近学习了plover的底层框架koa,所以下面这篇文章主要给大家介绍了关于利用Decorator如何控制Koa路由的相关资料,,文中通过示例代码介绍的非常详细,需要的朋友可以参考借鉴,下面来随着小编一起学习学习吧
    2018-06-06
  • Express框架实现简单拦截器功能示例

    Express框架实现简单拦截器功能示例

    这篇文章主要介绍了Express框架实现简单拦截器功能,结合实例形式分析了express框架拦截器相关功能与使用方法,需要的朋友可以参考下
    2023-05-05
  • 解决Node.js使用MySQL出现connect ECONNREFUSED 127.0.0.1:3306的问题

    解决Node.js使用MySQL出现connect ECONNREFUSED 127.0.0.1:3306的问题

    这篇文章主要介绍了解决Node.js使用MySQL出现connect ECONNREFUSED 127.0.0.1:3306报错的相关资料,文中将问题描述的很清楚,解决的方法也介绍的很完整,需要的朋友可以参考借鉴,下面来一起看看吧。
    2017-03-03

最新评论