主题
自定义Nest装饰器
上一篇盘点了nest中所有内置的装饰器, 这些装饰器已经能满足大部分的需求场景
对于一些特殊场景, 内置的装饰器可能满足不了
当装饰器过多的时候, 能否将多个装饰器合并成一个? 通过自定义装饰器就能实现
TIP
ES2016 装饰器是一个返回函数的表达式,可以将目标、名称和属性描述符作为参数。您可以通过在装饰器前添加一个@字符并将其放置在您要装饰的内容的最顶部来应用它。可以为类、方法或属性定义装饰器。
自定义参数装饰器
虽然nest提供了很多的参数装饰器,例如:@Param、@Query、@Body、@Req、@Res ....., 但是这些装饰器我们都可以通过自定义参数装饰器实现他们
通过createParamDecorator
创建一个参数装饰器
ts
import { createParamDecorator, ExecutionContext } from '@nestjs/common';
// 创建一个名叫User的参数装饰器
export const User = createParamDecorator(
(data: string, ctx: ExecutionContext) => {
const request = ctx.switchToHttp().getRequest();
const user = request.user;
return data ? user?.[data] : user;
},
);
上述装饰器中, data为装饰器传入的值
假如request.user
的数据格式为
json
{
"id": 101,
"firstName": "Alan",
"lastName": "Turing",
"email": "alan@email.com",
"roles": ["admin"]
}
装饰器使用方法同内置参数装饰器一样, 如下所示
ts
@Get()
// 通过@User('firstName')取到请求对象中的user中的firstName字段值
async findOne(@User('firstName') firstName: string) {
console.log(`Hello ${firstName}`);
}
自定义参数装饰器内使用Pipe
参数装饰器一般都会结合Pipe做参数校验, 自定义参数装饰器也一样, 使用方式同内置参数装饰器一样
也也可将管道直接用于自定义装饰器,但是必须注意加入参数validateCustomDecorators: true
才会生效
ts
@Get()
async findOne(
@User(new ValidationPipe({ validateCustomDecorators: true }))
user: UserEntity,
) {
console.log(user);
}
将多个装饰器合并为一个
Nest 提供了一个辅助方法来组合多个装饰器。例如,假设您想要将与身份验证相关的所有装饰器合并到一个装饰器中。这可以通过applyDecorators
来完成:
ts
import { applyDecorators } from '@nestjs/common';
export function Auth(...roles: Role[]) {
return applyDecorators(
SetMetadata('roles', roles),
UseGuards(AuthGuard, RolesGuard),
ApiBearerAuth(),
ApiUnauthorizedResponse({ description: 'Unauthorized' }),
);
}
然后您可以@Auth()按如下方式使用此自定义装饰器:
ts
@Get('users')
@Auth('admin')
findAllUsers() {}
小结
内置装饰器不够用的时候,或者想把多个装饰器合并成一个的时候,都可以自定义装饰器。
方法的装饰器就是传入参数,调用下别的装饰器就好了,比如对 @SetMetadata
的封装。
如果组合多个方法装饰器,可以使用 applyDecorators
api。
class 装饰器和方法装饰器一样。
还可以通过 createParamDecorator
来创建参数装饰器,它能拿到 ExecutionContext
,进而拿到 reqeust
、response
,可以实现很多内置装饰器的功能,比如 @Query
、@Headers
等装饰器。
通过自定义方法和参数的装饰器,可以让 Nest 代码更加的灵活。