Обработка нескольких типов ответов от одного и того же API в Angular - PullRequest
2 голосов
/ 20 июня 2020

Я новичок в Angular. Я работал над сервисом, который извлекает определенные данные из API и возвращает наблюдаемое. API может возвращать два типа ответов JSON, массив настраиваемых типов данных или настраиваемый код ошибки и сообщение в случае некоторой внутренней ошибки на сервере. Я создал два интерфейса, скажем I1 и I2, в соответствии с двумя возможными ответами. Оба ответа JSON, возвращаемые API, также соответствуют одной и той же структуре соответственно.

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 ]

1 голос
/ 20 июня 2020

Измените свой метод 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));
0 голосов
/ 20 июня 2020

Я не уверен, почему вы подписываетесь на услугу, но это анти-шаблон.

Если переменная 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, чтобы получить полный контроль над запросом.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...