@kttotto
пофиг на чем писать

Как вернуть Observable с агрегированным результатом других Observable?

Столкнулся с библиотекой rxjs, с которой раньше не приходилось иметь дело.
Есть задача, не совсем понимаю как по уму сделать.
Есть несколько запросов, которые возвращают Observable с результатом или 500.
Мне нужно вернуть Observable с агрегированным результатом этих запросов, запросы должны выполниться все, ошибки показать в консоли.

Подскажите на какие методы смотреть.
  • Вопрос задан
  • 334 просмотра
Решения вопроса 3
EreminD
@EreminD
Кое-что умею
https://blog.angularindepth.com/learn-to-combine-r...
Тут про все возможные способы объединения
Выберите подходящий и посмотрите, как использовать его
Кажется, вам нужен zip
Ответ написан
Xuxicheta
@Xuxicheta Куратор тега Angular
инженер
forkJoin, catchError, tap
forkJoin должен думать что все потоки успешно завершились, т.е. для каждого запроса нужно сделать обертку, которая перехватит ошибку, обработает и успешно завершит поток.
Ответ написан
@kttotto Автор вопроса
пофиг на чем писать
Спасибо всем за соучастие. Все заработало как задумано, сам метод получился вполне рабочим, может кому реальный пример поможет. Если можно было сделать проще или "правильнее" - не стесняемся комментировать.

PS: В чем заключалась проблема, так сказать мотивация)
Есть внешний api, который принимает массив параметров, в ответ он возвращает один объект.
Но на один из параметров он внутри падает с 500-ой. Как временное решение этой проблемы: сначала пытаемся получить ответ по всему массиву, если падает с ошибкой, то делаем запросы по одному, по каждому параметру, ответы собираем в один объект. Если по какому то параметру падает запрос, то вместо реального ответа возвращаем объект заглушку, без обрыва всей цепочки запросов.

spoiler
getUserDictByLogins(logins: string[]): Observable<UserDict> {
    if (!logins || logins.length === 0) {
      return of({});
    }

    return this.getUsersByLogins(logins)
      .pipe(
        map(users => {
          const userDict = {};
          users.forEach(u => userDict[u.accountName] = u);
          return userDict;
        }),
        catchError(err => {
          console.log(err.data);
          return this.getUserDictOneByOne(logins);
        })
      );
  }

  private getUserDictOneByOne(logins: string[]): Observable<UserDict> {
    const observables: Observable<UserDict>[] = [];

    logins.forEach(login => {
      observables.push(this.getUsersByLogins([login])
        .pipe(
          map(users => {
            const userDict = {};
            users.forEach(u => userDict[u.accountName] = u);
            return userDict;
          }),
          catchError(err => {
            console.log("Error getting user data: ", login);
            console.log(err.data);
            const userDict = {};
            const userBean = {
              accountName: login,
              displayName: login,
              name: login,
              fioShort: login,
              iofShort: login
            };
            userDict[login] = userBean;
            return of(userDict);
          })));
    });

    return forkJoin(observables)
      .pipe(
        map((userDicts) => {
          const userDict = {};
          userDicts.forEach(u => Object.assign(userDict, u));
          return userDict;
        })
    );
  }
Ответ написан
Пригласить эксперта
Ваш ответ на вопрос

Войдите, чтобы написать ответ

Похожие вопросы