在Angular中处理来自同一API的多种响应类型

时间:2020-06-20 08:08:55

标签: angular rxjs observable httpclient

我对Angular很陌生。我一直在研究一种服务,该服务从API提取某些数据并返回可观察到的结果。如果服务器中发生内部错误,API可以返回两种类型的JSON响应:自定义数据类型的数组或自定义错误代码和消息。根据这两种可能的响应,我创建了两个接口,例如I1I2。 API返回的两个JSON响应也分别遵循相同的结构。

interface I1 {
  responseData: customData[]
}

interface I2 {
  errorCode: number,
  errorMessage: string
}

对于服务本身,我想编写一个函数,该函数首先获取数据并检查接收到的类型。如果类型为I1,则它将返回I1中数组的可观察值,或者如果类型为I2,则它将在控制台上记录错误并返回错误对象。我已经在服务类中编写了一个函数:

APIResponse: I1 | I2;

getData(): Observable<CustomData[] | I2> {
  this.http.get<I1 | I2>('url/to/api').subscribe(res => {
    this.APIResponse = res;
  });

  if('errorCode' in this.APIResponse) {
    console.log(this.APIResponse.errorCode);
    return of(this.APIResponse);
  }
  else if('responseData' in APIResponse) {
    return of(this.APIResponse.responseData);
  }
}

现在,此代码在编译时显示错误,因为this.APIResponse的类型与该函数为其返回值所期望的类型不同。我可以将函数的返回类型更改为Observable<I1 | I2>,但是我将无法仅返回数组。我无法以任何方式更改API结构。我尝试将APIResponse发生错误时分配给类型为I2的中间变量,然后从函数中返回它,但是它不允许我将类型'I1 | I2'分配给类型'I2'

我应该如何从这里开始以获得期望的结果?

2 个答案:

答案 0 :(得分:1)

将getData方法更改为:-

getData(): Observable<CustomData[] | I2> {
  return this.http.get('url/to/api').pipe(map((res : I1|I2) => {
    if('errorCode' in res) {
       this.APIResponse = res;  
       console.log(this.APIResponse.errorCode);
       return res;
    } else {
         this.APIResponse = res;
         return res.responseData;
    }
  }));
}

任何想使用此方法的地方,都可以像这样使用它:-

getData().subscribe((res) => console.log(res));

答案 1 :(得分:0)

我不确定您为什么要订阅服务,但这是反模式的。

如果APIResponse变量仅在getData()函数中用于创建新的可观察对象,则不需要它。

要记录响应或执行任何副作用,请使用tap运算符。

getData(): Observable<CustomData[] | I2> {
    return this.http.get<I1 | I2>('url/to/api').pipe(
      map(res => {
        if ('responseData' in res) {
          return res.responseData;
        } else if ('errorCode' in res) {
          return res;
        }
      }),
      tap(res => {
        // Side effects

        if ('errorCode' in res) {
          console.log(res.errorCode);
        }
      }),
    );
  }

如果使用APIResponse变量并希望为其分配响应,则必须在tap运算符中进行操作,因为这是副作用。

  tap(res => {

    // Assign value to APIResponse;

    this.APIResponse = res;
  })

最后,要从服务器获取数据,请订阅组件中的getData()可观察流。

this._service.getData().subscribe(data => { // do what you want with data })

如果您的服务使用除2xx之外的代码发送错误响应,则可以使用catchError运算符或使用http选项来完全控制请求。