【问题标题】:Nest JS Factorize Error handling in resolverNest JS Factorize 解析器中的错误处理
【发布时间】:2022-11-16 01:14:41
【问题描述】:

我有一个我的用户的解析器文件,上面有一些突变来更新、删除、markInactive 和 banUser

  async updateUser(
    @Args() { id, input },
  ) {
    const user = await this.userService.getById(id);
    if (!user) {
      return new NotFoundError('User not found');
    }

    const isAdminUser = this.userService.isUserAdmin(id);
    if (!isAdminUser) {
      return new PermissionError(`You can't update this user cause it's an admin `);
    }

    const user = await this.userService.update(id, input);

    return {
      id: user.id,
      user
    };
  }


 async deleteUser(
    @Args() { id, input },
  ) {
    const user = await this.userService.getById(id);
    if (!user) {
      return new NotFoundError('User not found');
    }

    const isAdminUser = this.userService.isUserAdmin(id);
    if (!isAdminUser) {
      return new PermissionError(`You can't update this user cause it's an admin`);
    }

    const user = await this.userService.delete(id, input);

    return {
      id: user.id,
      user
    };
  }

 async deleteUser(
    @Args() { id, input },
  ) {
    const user = await this.userService.getById(id);
    if (!user) {
      return new NotFoundError('User not found');
    }

    const isAdminUser = this.userService.isUserAdmin(id);
    if (!isAdminUser) {
      return new PermissionError(`You can't update this user cause it's an admin`);
    }

    const user = await this.userService.delete(id, input);

    return {
      id: user.id,
      user
    };
  }

 async markInactive(
    @Args() { id },
  ) {
    const user = await this.userService.getById(id);
    if (!user) {
      return new NotFoundError('User not found');
    }

    const isAdminUser = this.userService.isUserAdmin(id);
    if (!isAdminUser) {
      return new PermissionError(`You can't update this user cause it's an admin`);
    }

    const user = await this.userService.markInactive(id);

    return {
      id: user.id,
      user
    };
  }


 async banUser(
    @Args() { id },
  ) {
    const user = await this.userService.getById(id);
    if (!user) {
      return new NotFoundError('User not found');
    }

    const isAdminUser = this.userService.isUserAdmin(id);
    if (!isAdminUser) {
      return new PermissionError(`You can't update this user cause it's an admin`);
    }

    const user = await this.userService.banUser(id);

    return {
      id: user.id,
      user
    };
  }

我总是在我的所有解析器中重复错误处理程序(检查用户是否存在并检查用户是否为管理员),现在我需要添加两个更新突变,但我想找到一种方法将此错误检查分解为一个通用函数

您有实现此目标的解决方案吗?

【问题讨论】:

    标签: javascript graphql nestjs


    【解决方案1】:

    这里有很好的重构用例。我会建议你两种方法。请注意,某些部分只是猜测,因为我不知道您的代码库。

    使用重复的方法

    由于这些方法做同样的事情,您可以将逻辑移到其他地方:

    @Injectable()
    export class UserService {
      async getById(userId: string): Promise<User> {
        // just an example 
        const user = { id: '1', isAdmin: false };
    
        return Promise.resolve(user);
      }
    
      async ensuresUserExists(userId: string): Promise<void> {
        const user = await this.getById(userId);
    
        if (!user) {
          throw new NotFoundError('User not found');
        }
      }
    
      async ensuresUserIsNotAdmin(userId: string): Promise<void> {
        const user = await this.getById(userId);
    
        if (!user) {
          throw new PermissionError("You can't update this user cause it's an admin");
        }
      }
    }
    
    

    您可以在控制器方法中简单地使用它:

      async updateUser(
        @Args() { id, input },
      ) {
        await this.userService.ensuresUserExists(id);
        await this.userService.ensuresUserIsNotAdmin(id);
    
        const user = await this.userService.update(id, input);
    
        return {
          id: user.id,
          user
        };
      }
    
    

    我认为如果用户无论如何都不存在,大多数 ORM 都会抛出错误,我假设您可以更深入地确保用户存在并且不是管理员,但我还是不知道您的架构是什么。

    使用守卫

    NestJs 允许您创建自定义 guards,您可以在其中执行方法执行之前的任何操作。 IMO 是一种更清洁的方法。

    守卫.ts

    export const ADMIN_OP = 'admin';
    
    @Injectable()
    export class UserEditGuard implements CanActivate {
      constructor(private reflector: Reflector, private userService: UserService) {}
    
      async canActivate(context: ExecutionContext): Promise<boolean> {
        const request = context.switchToHttp().getRequest();
    
        const operationType = this.reflector.get<string>(
          'operationType',
          context.getHandler(),
        );
    
        if (operationType !== ADMIN_OP) return true;
    
        const { userId } = request.body; // assuming you are sending params in POST request body
    
        if (!userId) {
          throw new UnauthorizedException(); 
        }
    
        await this.userService.ensuresUserExists(userId);
        await this.userService.ensuresUserIsNotAdmin(userId);
    
        return true;
      }
    }
    

    现在你只需要将守卫“插入”到你的方法中。

    export const UserPermissionCheck = () => SetMetadata('operationType', ADMIN_OP); // This will add the type to metadata
    

    然后将它添加到您的控制器(这也适用于服务)

    
    @Controller()
    @UseGuards(UserEditGuard)
    export class UserController {
      constructor(private readonly userService: UserService) {}
    
      @Post()
      @UserPermissionCheck()
      async updateUser(@Body() { id, input }) {
        const user = await this.userService.update(id, input);
    
        return {
          id: user.id,
          user,
        };
      }
    
      @Post()
      @UserPermissionCheck()
      async deleteUser(@Body() { id, input }) {
        const user = await this.userService.delete(id, input);
    
        return {
          id: user.id,
          user,
        };
      }
    }
    

    【讨论】:

      猜你喜欢
      • 2021-06-04
      • 2016-02-07
      • 1970-01-01
      • 2020-03-06
      • 2017-10-09
      • 2021-06-12
      • 1970-01-01
      • 1970-01-01
      • 2011-03-11
      相关资源
      最近更新 更多