如何处理 Observable 中的多个 catchError?

How to handle multiple catchError in Observable?

第一次使用 NestJs 和 Observables。我很熟悉如何使用 Promises 解决这个问题,但我想扩展我对 Observables 的了解。

下面是一个“注册”功能,需要做几件事。首先,它创建租户,然后根据租户的结果创建用户。

如果租户或用户已经存在,则会引发违反唯一约束的错误。如果发生错误,我想做的是从 observable 中解救出来,并将 return 错误发送给控制器。在捕捉到第一个错误时最终会发生什么,它将在第二个“catchError”

中再次被捕捉到

我已经在下面的第二个“catchError”中处理了这个问题(通过查找 BadRequestException),但这感觉不对。我的问题是是否有更好的方法来处理这个问题?

提前致谢!

signup(signUpDto: SignupRequestDto, tenantDto: TenantDto): Observable<User> {
  const createTenant$ = from(
    this.createTenant(tenantDto.name, tenantDto.key),
  );

  const user = createTenant$.pipe(
    catchError((error, caught) => {
      const err = error as PrismaClientKnownRequestError;
      this._logger.error({ err, caught }, 'tenant err');

      // Unique constraint violation
      if (err.code === 'P2002') {
        throw new BadRequestException(
          'Tenant already exists',
          tenantDto.name,
        );
      } else {
        throw new InternalServerErrorException('Error creating user');
      }
    }),
    switchMap((tenant) => {
      return from(this.createUser(signUpDto, tenant.id));
    }),
    catchError((error, caught) => {
      // If this is error is already handled by the catchError above
      if (error instanceof BadRequestException) {
        throw error;
      } else {
        const err = error as PrismaClientKnownRequestError;
        this._logger.error({ err, caught }, 'user err');

        // Unique constraint violation
        if (err.code === 'P2002') {
          throw new BadRequestException('Email already exists');
        } else {
          throw new InternalServerErrorException('Error creating user');
        }
      }
    }),
  );

  return user;
}

您可以使用单个 catchError 来实现它,但问题是识别 来源 。为此,我使用了一个私有变量来识别来源。

private currentEvent: string = 'createTenant'; //default value createTeanant

  private currentEvent: string = 'createTenant';
  signup(signUpDto: SignupRequestDto, tenantDto: TenantDto): Observable<User> {
    
    const createTenant$ = from(
      this.createTenant(tenantDto.name, tenantDto.key)
    );
    return user = createTenant$.pipe(
      switchMap((tenant) => {
        
        currentEvent = 'createUser';//Assigning new event name
        
        return from(this.createUser(signUpDto, tenant.id));
      }),
      catchError((error, caught) => {
        const err = error as PrismaClientKnownRequestError;

        this._logger.error({ err, caught }, this.currentEvent + ' err');

        // Unique constraint violation
        if (err.code === 'P2002' && this.currentEvent === 'createTenant') {
          throw new BadRequestException(
            'Tenant already exists',
            tenantDto.name
          );
        } else if (err.code === 'P2002' && this.currentEvent === 'createUser') {
          throw new BadRequestException('Email already exists');
        } else {
          throw new InternalServerErrorException('Error creating user');
        }
      })
    );
  }