【问题标题】:Observable transformation to handle backend server error用于处理后端服务器错误的可观察转换
【发布时间】:2020-05-25 18:52:14
【问题描述】:

对于关于 RxJS 的新手/转储问题,我刚开始学习 Angular 表示歉意。

所以我创建了一个异步验证器静态方法,它调用一个 API 服务方法来检查数据库中用户名的唯一性。下面的代码 sn-ps 在后端服务器启动并运行时工作。如果不是,它会打印一条错误日志消息,我应该在演示组件中处理它。

在处理此类泛型用例以将Observable<SuccessResponse>Observable<ErrorResponse> 转换为Observable<ValidationErrors | null> 的转换步骤中缺少什么。

验证器

static usernameUnique(service: ApiService): AsyncValidatorFn {
    return (control: FormControl): Observable<ValidationErrors | null> => {
        return service.isUsernameTaken(control.value as string)
            .pipe(
                map((response: SuccessResponse) => response.data ? { taken: true } : null)
            );
    };
}

ApiService

isUsernameTaken(username: string): Observable<SuccessResponse | ErrorResponse> {
    return this.httpCient.get('/backend/account/checkUnique', { params: { username: username } })
                .pipe(catchError(this.handleError));
}

handleError(error: HttpErrorResponse) : Observable<ErrorResponse> {
    // return specific payload of ErrorResponse based on error.status
}

提前致谢。

【问题讨论】:

    标签: angular rxjs rxjs-pipeable-operators rxjs-observables


    【解决方案1】:

    我不确定您在哪里遇到问题。如果您尝试将映射解析为验证器内的 ValidationErrors,则需要检查类型。在此示例中,我返回了一个名为“apiError”的错误以区别于“taken”错误,但我不确定您选择如何在您的应用程序中处理这种情况。

    我假设ErrorResponse 包含一个error 字段,而SuccessResponse 包含一个data 字段。

    static usernameUnique(service: ApiService): AsyncValidatorFn {
      return (control: FormControl): Observable<ValidationErrors | null> => {
        return this.isUsernameTaken(control.value as string)
          .pipe(
            map(response => {
              if ('error' in response) { // response is ErrorResponse
                return { apiError: response.error };
              }
              return response.data ? { taken: true } : null;
            })
          );
      };
    

    如果您使用new ErrorResponse()new SuccessResponse() 构造实际的类实例,则可以使用intanceof 而不是使用in 运算符检查字段。例如if (response instanceof ErrorResponse).

    或者,您可以将错误冒泡回验证器,并在另一个catchError 中处理响应。我更喜欢这种方式,因为 api 的响应没有条件逻辑。

    验证器

    static usernameUnique(service: ApiService): AsyncValidatorFn {
      return (control: FormControl): Observable<ValidationErrors | null> => {
        return this.isUsernameTaken(control.value as string)
          .pipe(
            map(response => response.data ? { taken: true } : null),
            catchError((err: ErrorResponse) => of({ apiError: err.error }))
          );
      };
    }
    

    ApiService

    isUsernameTaken(username: string): Observable<SuccessResponse> {
      return this.http.get('/backend/account/checkUnique', { params: { username } })
        .pipe(
          map(response => response as SuccessResponse), // maps the api response to SuccessResponse
          catchError(this.handleError) // maps the error to ErrorResponse
        );
    }
    
    handleError(error: HttpErrorResponse): Observable<never> {
      let errorResponse: ErrorResponse;
      // specific payload of ErrorResponse based on error.status
    
      return throwError(errorResponse);
    }
    
    

    【讨论】:

    • pipe(map, catchError) 组合是我现在正在寻找的。非常感谢。
    猜你喜欢
    • 1970-01-01
    • 2017-09-04
    • 1970-01-01
    • 1970-01-01
    • 2018-08-12
    • 2017-04-06
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多