Skip to content

自定义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,进而拿到 reqeustresponse,可以实现很多内置装饰器的功能,比如 @Query@Headers 等装饰器。

通过自定义方法和参数的装饰器,可以让 Nest 代码更加的灵活。