nest.js 自定义路由参数装饰器——迹忆客-ag捕鱼王app官网
nest 是围绕一种称为装饰器的语言特性构建的。 装饰器是许多常用编程语言中的一个众所周知的概念,但在 javascript 世界中,它们仍然相对较新。 为了更好地理解装饰器是如何工作的,我们推荐阅读这篇文章。 这是一个简单的定义:
es2016 装饰器是一个表达式,它返回一个函数,可以将目标、名称和属性描述符作为参数。 你可以通过在装饰器前面加上一个 @ 字符来应用它,并将它放在你要装饰的东西的最上面。 可以为类、方法或属性定义装饰器。
参数装饰器
nest 提供了一组非常实用的参数装饰器,可以结合 http 路由处理器(route handlers)一起使用。下面的列表展示了nest 装饰器和原生 express(或 fastify)中相应对象的映射。
装饰器 | 对象 |
---|---|
@request(),@req() | req |
@response(),@res() | 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 |
@hostparam() | req.hosts |
此外,我们可以创建自己的自定义装饰器。 为什么这很有用?
在 node.js 世界中,将属性附加到请求对象是常见的做法。 然后在每个路由处理程序中手动提取它们,使用如下代码:
const user = req.user;
为了使代码更具可读性和透明性,我们可以创建一个 @user()
装饰器并在所有控制器中重用它。
user.decorator.ts
import { createparamdecorator, executioncontext } from '@nestjs/common'; export const user = createparamdecorator( (data: unknown, ctx: executioncontext) => { const request = ctx.switchtohttp().getrequest(); return request.user; }, );
然后,我们可以在适合自己要求的任何地方简单地使用它。
@get()
async findone(@user() user: userentity) {
console.log(user);
}
传递数据
当装饰器的行为取决于某些条件时,可以使用 data 参数将参数传递给装饰器的工厂函数。 一个用例是自定义装饰器,它通过键从请求对象中提取属性。 例如,假设我们的身份验证层验证请求并将用户实体附加到请求对象。 经过身份验证的请求的用户实体可能类似于:
{
"id": 101,
"firstname": "alan",
"lastname": "turing",
"email": "alan@email.com",
"roles": ["admin"]
}
让我们定义一个装饰器,它以属性名作为键,如果存在则返回关联的值(如果不存在,则返回 undefined,或者如果用户对象尚未创建)。
import { createparamdecorator, executioncontext } from '@nestjs/common';
export const user = createparamdecorator(
(data: string, ctx: executioncontext) => {
const request = ctx.switchtohttp().getrequest();
const user = request.user;
return data ? user?.[data] : user;
},
);
以下是我们如何通过控制器中的 @user()
装饰器访问特定属性的方法:
@get()
async findone(@user('firstname') firstname: string) {
console.log(`hello ${firstname}`);
}
我们可以使用具有不同键的相同装饰器来访问不同的属性。 如果用户对象很深或很复杂,这可以使请求处理程序实现更容易和更易读
提示
: 对于 typescript 用户,请注意 createparamdecorator() 是一个泛型。 这意味着我们可以显式地强制执行类型安全,例如 createparamdecorator ((data, ctx) => ...)。 或者,在工厂函数中指定参数类型,例如 createparamdecorator((data: string, ctx) => ...)。 如果两者都省略,则 data 的类型将为 any。
使用管道
nest 以与内置参数(@body()、@param() 和 @query())相同的方式处理自定义参数装饰器。 这意味着也为自定义注释参数执行管道(在我们的示例中,用户参数)。 此外,我们可以将管道直接应用于自定义装饰器:
@get()
async findone(
@user(new validationpipe({ validatecustomdecorators: true }))
user: userentity,
) {
console.log(user);
}
注意
,validatecustomdecorators 选项必须设置为 true。 默认情况下,validationpipe 不验证使用自定义装饰器注释的参数。
装饰器组成
nest 提供了一个辅助方法来组合多个装饰器。 例如,假设我们想将所有与身份验证相关的装饰器组合成一个装饰器。 这可以通过以下结构来完成:
auth.decorator.ts
import { applydecorators } from '@nestjs/common'; export function auth(...roles: role[]) { return applydecorators( setmetadata('roles', roles), useguards(authguard, rolesguard), apibearerauth(), apiunauthorizedresponse({ description: 'unauthorized' }), ); }
然后,我们可以使用此自定义 @auth() 装饰器,如下所示:
@get('users')
@auth('admin')
findallusers() {}
这具有通过单个声明应用所有四个装饰器的效果。
警告
: @nestjs/swagger 包中的 @apihideproperty() 装饰器不可组合,并且无法与 applydecorators 函数一起正常工作。