Search code examples
angularrxjsobservablehttpclient

Handling multiple response types from same API in Angular


I am fairly new to Angular. I've been working on a service which fetches certain data from an API and returns an observable. The API can return two types of JSON responses, an array of custom data type or a custom error code and message in case of some internal error in the server. I have created two interfaces, say I1 and I2, according to the two possible responses. Both the JSON responses returned by the API also follow the same structures respectively.

interface I1 {
  responseData: customData[]
}

interface I2 {
  errorCode: number,
  errorMessage: string
}

For the service itself, I want to write a function which first fetches the data and checks it for the type received. If the type is I1, then it will return the observable of the array in I1 or if the type is I2, then it will log the error on console and also return the error object. I have written a function in the service class:

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);
  }
}

Now this code shows errors while compiling because the type of this.APIResponse is not same as expected by the function for its return value. I can change the return type of the function to Observable<I1 | I2> but then I will not be able to return just the array. I cannot change the API structure in any way. I have tried assigning the APIResponse in case of error to an intermediate variable of type I2 and then returning it from the function, but it does not let me assign type 'I1 | I2' to a type 'I2'.

How should I proceed from here to get the desired result?


Solution

  • Change your getData method to :-

    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;
        }
      }));
    }
    

    Any where you want to use this method, use it like :-

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