NestJS 9 GraphQL 中文文档(十三) - 扩展

131 阅读2分钟

Nest 最新的版本为V9,较之前的V7/8有不小改动,GraphQL 部分官方文档之前的V8也是本人翻译的,有很多不完善的地方,这次打算重新精细翻译一遍,会持续更新这块内容,并最后贡献给中文文档仓库,为中文社区贡献一份力量。有兴趣的小伙伴记得要关注收藏。

警告 ⚠️
此章节仅适用于代码优先方式

扩展是一种高级的低级功能,可让你在类型配置中定义任意数据。将自定义元数据附加到某些字段允许你创建更复杂、通用的解决方案。例如,有了扩展,你可以定义访问特定字段所需的角色。此类角色可以在运行时反映出来,以确定调用者是否拥有足够的权限来检索特定字段。

添加自定义元数据

要为一个字段附加自定义元数据,使用从@nestjs/graphql包里导出的@Extensions() 装饰器即可。

@Field()
@Extensions({ role: Role.ADMIN })
password: string;

在上面的示例中,我们role元数据属性分配了Role.ADMIN的值。Role是一个简单的TypeScript枚举,它对我们系统中可用的所有用户角色进行分组。

注意,除了可以在字段上设置元数据,你还可以在类级别和方法级别(例如,在查询处理器上)使用@Extensions() 装饰器。

使用自定义元数据

利用自定义元数据的逻辑可以根据需求复杂化。例如,你可以创建一个简单的拦截器,来存储或记录每个方法调用的事件,或一个字段中间件来匹配检索具有调用者权限的字段所需的角色(字段级权限系统)。

出于说明目的,让我们定义一个checkRoleMiddleware将用户的角色(此处硬编码)与访问目标字段所需的角色进行比较:

export const checkRoleMiddleware: FieldMiddleware = async (
  ctx: MiddlewareContext,
  next: NextFn,
) => {
  const { info } = ctx;
  const { extensions } = info.parentType.getFields()[info.fieldName];

  /**
   * In a real-world application, the "userRole" variable
   * should represent the caller's (user) role (for example, "ctx.user.role").
   */
  const userRole = Role.USER;
  if (userRole === extensions.role) {
    // or just "return null" to ignore
    throw new ForbiddenException(
      `User does not have sufficient permissions to access "${info.fieldName}" field.`,
    );
  }
  return next();
};

有了这些,我们就可以为password字段注册中间了,如下所示:

@Field({ middleware: [checkRoleMiddleware] })
@Extensions({ role: Role.ADMIN })
password: string;