Nest —— Custom decorators

1,790 阅读5分钟

前言

       之前匆匆写了一篇关于Nest官文的翻译,然而写的时候比较着急,所以很多地方的翻译比较马虎,甚至直接丢进翻译器在丢出来....(有的时候我会被丢进翻译器之后被丢出来的译文吓到,原因是...译文比自己翻译的好/(ㄒoㄒ)/~~)但还是有很多部分是翻译器解决不了的,语句通顺固然优雅锦上添花,但一点小的错误却是致命的。
       现在手头比较悠闲,也打算重新修改一份比较优雅的中文文档。有人会问花这么多时间写这个东西,是不是真的有用。百度上面也有一些关于Nest的文档,完全也不会有人来看你写的翻译。我的感受是,可能这就是我的学习方式吧。其实平时阅读文档,大多数情况下都是脑子说会了,手说不会。一边翻译英文文档,一遍理解框架的含义,还有助于提高阅读英文文档的能力。手敲过一遍和眼睛看过一遍真的不太一样,而且这种方式会增加使用时的自信。之后打算将每一章节分开书写,最后再通过链接汇总到一篇Nest妲己大记中去。就算没有人看,自己想要翻阅文档的时候,也可以拿出来看看,还能改改。这是一种乐趣,就好像养成游戏一样。



正文 Custom decorators

Custom route decorators 自定义路由装饰器

Nest是围绕着装饰器这个语言特性构建的。装饰器在许多常用的编程语言中众所周知的概念。

ES2016标准中的装饰器是一个表达式,它返回一个函数并可以将目标,名称,属性描述符作为函数的参数。你需要通过在装饰器前添加@字符前缀并把它放在你想要装饰的东西的最顶端来应用它。我们可以为一个类或者一个属性定义装饰器。



Param decorators 参数装饰器

Nest提供了一组有用的参数装饰器,你可以将它与Http路由处理程序一起使用。下面的表格提供了装饰器以及他们所代表的的纯Express对象。

@Request() req
@Response() res
@Next() next
@Session() req.session
@Param(param?: string) req.params/req.params[param]
@Body(param?: string) req.body/req.body[param]
@Query(param?: string) req.query/req.query[param]
@Headers(param?: string) req.headers/req.headers[param]
@Ip() req.ip

此外,你也可以创建自己的自定义装饰器。

在node.js中,将属性附加在请求对象上是一种惯例。然后你可以在每个路由处理程序中手动地提取到他们,然后像下面这样去使用:

const user = req.user

为了让你的代码更具有清晰和可读性,你可以创建一个 @User() 装饰器并且在你的控制器中重复使用。

//user.decorator.ts
import { createParamDecorator } from '@nestjs/common'

export const User = createParamDecorator((data, req) => {
  return req.user
})

然后你就可以在任何需要的地方去使用他。

@Get()
async findOne(@User() user: UserEntity) {
  console.log(user)
}



Passing data 传入data参数

当装饰器的行为依赖于某些情况时,你可以将data参数传入装饰器的工厂函数中。一种使用场景是自定义装饰器通过key来提取请求对象上的属性。例如,我们的权限验证层需要验证请求并将一个用户实体附加在请求对象上。用户实体看起来像这样:

{
  "id": 101,
  "firstName": "Alan",
  "lastName": "Turing",
  "email": "alan@email.com",
  "roles": ["admin"]
}

让我们定义一个装饰器,接受一个属性名作为key,并返回相关的值(如果不存在返回undefined,或者甚至没有user对象)

//user.decorator.ts
import { createPramDecorator } from '@nestjs/common'

export const User = createParamDecorator((data: string, req) => {
  return data ? req.user && req.user[data] : req.user
})

现在你可以在控制器中通过 @User() 获取到想要的属性。

@Get()
async findOne(@User('firstName') firstName: string) {
  console.log(`Hello ${firstName}`)
}

你可以用同一个装饰器,根据不同的key值获取不同的属性。如果user对象是深层的复杂结构,这样可以使请求处理的实现更容易且可读。



Working with pipes 结合管道使用

Nest将自定义参数装饰器和内置的装饰器一视同仁。这意味着管道对自定义注视参数也是生效的,你可以直接对自定义装饰器使用管道。

@Get()
async findOne(@User(new ValidationPipe()) user: UserEntity) {
  console.log(user)
}



Decorator composition 装饰器的构成

Nest提供了一个辅助函数来组建多个装饰器。例如,假设你想要结合所有与权限相关的装饰器到单个装饰器中。你可以以以下方式构建:

import { applyDecorators } from '@nestjs/common'

export function Auth(...roles: Rolep[]) {
  SetMetadata('roles', roles),
  UseGuards(AuthGuard, RolesGuard),
  ApiBearerAuth(),
  ApiUnauthorizedResponse({ description: 'Unauthorized' })
}

然后你就可以如下方式使用 @Auth() 装饰器。

@Get('users')
@Auth('admin')
findAllUsers() {}





后记

原文地址: docs.nestjs.com/custom-deco…


关于本文

  • 文章非复制黏贴,经浏览文档,以自己的理解进行,代码测试,手打书写。本篇为翻译+意译。
  • 用作记录自己曾经学习、思考过的问题的一种笔记。
  • 用作前端技术交流分享。
  • 阅读本文时欢迎随时质疑本文的准确性,将错误的地方告诉我。本人会积极修改,避免文章对读者的误导。

关于我

  • 是一只有梦想的肥柴。
  • 觉得算法、数据结构、函数式编程、js底层原理等十分有趣的小前端。
  • 志同道合的朋友请关注我,一起交流技术,在前端之路上共同成长。
  • 如对本人有任何意见建议尽管告诉我哦~ 初为肥柴,请多多关照~
  • 前端路漫漫,技术学不完。今天也是美(diao)好(fa)的一天( 跪了...orz