Вложенные ApiCalls с угловым HttpClient и RxJS - PullRequest
0 голосов
/ 08 ноября 2018

Итак, у меня есть сервер, который по запросу возвращает массив объектов

Пример:

[
  {
   id: 1
   name: name1
  },
  {
   id: 2
   name: name2
  }
]

Массив может иметь бесконечные элементы;

После этого мне нужно отправитьновые запросы для каждого элемента в массиве с идентификатором ответа.

пример:

https://localhost/api/parent/${id}/child

ответ:

[
  {
   childId: 1
   name: name1
  },
  {
   childId: 2
   name: name2
  },
  {
   childId: 3
   name: name3
  }
]

И после этого я должен отправить новые запросы накаждый ответ на новые запросы

пример:

https://localhost/api/parent/${id}/child/${childId}/grandChild

ответ:

[
  {
   grandChildId: 1
   name: name1
  },
  {
   grandChildId: 2
   name: name2
  },
  {
   grandChildId: 3
   name: name3
  }
]

и ответ похож на другие

и после этого у меня естьорганизовать данные так, чтобы они выглядели так:

[
  {
   id: 1
   name: name1
   children: [
            {
              childId: 1
              name: name1,
              grandChildren: [
                            {
                             grandChildId: 1
                             name: name1
                            },
                            {
                             grandChildId: 2
                             name: name2
                            },
                            {
                             grandChildId: 3
                             name: name3
                            }
                            ]
            },
            {
             childId: 2
             name: name2
            },
            {
            childId: 3
            name: name3
            }
        ]
  },
  {
   id: 2
   name: name2
  }
]

У каждого родителя есть массив детей, а у каждого ребенка - массив grandChildren.

Это была моя попытка, но если я попробую в компоненте сделать родителей.forEach (parent => console.log (parent.childern)) не определено

getData() {

return this.http.get<Parent[]>(baseUrl + 'parent', {withCredentials: true}).pipe(
      map(parents => {
        parents.forEach(parent => {
          this.getChildren(parent).subscribe(Children => {
            parent.Children = Children;
            parent.Children.forEach(Children => {
              this.getGrandChildren(Children).subscribe(grandChild => {
                Children.grandChildren = grandChild;
              });
            });
          });
        });
      return parents;
      })
        );

}

 getChildren(parent: Parent): Observable<Child[]> {
  return this.http.get<Children[]>(baseUrl + `parent/${parent.id}/children`, {withCredentials: true});

}

 getGrandChildren(child: Child): Observable<GrandChild[]> {
return this.http.get<GrandChild[]>(baseUrl + `children/${child.id}/GrandChildren`, {withCredentials: true});

}

Ответы [ 4 ]

0 голосов
/ 09 ноября 2018

Глядя на вашу проблему, она кажется рекурсивной.

Parent , Child , GrandChild все похожи и выглядят как плоское представление узлов и листьев дерева. Если это так, вы можете посмотреть this , чтобы узнать, как выполнить рекурсивную обработку с RxJS.

Строго придерживаясь того, как вы представляли свою проблему, по крайней мере, до моего понимания, вот способ ее решения

getParents()
.pipe(
  switchMap(parents => from(parents)),
  mergeMap(parent => getChildren(parent)
    .pipe(
      switchMap(children => from(children)),
      mergeMap(child => getGrandChildren(child)
        .pipe(
          tap(grandChildren => child.grandChildren = grandChildren),
          map(() => child)
        )
      ),
      toArray(),
      tap(children => parent.children = children),
      map(() => parent)
    ), 1  // cuncurrency set to 1 to guarantee same order
  ),
)
.subscribe(d => console.log(JSON.stringify(d, null, 2)))

Я проверил его со следующими данными моделирования и функциями

const parents = [
  {id: 1, name: 'name1'},
  {id: 2, name: 'name2'},
];
const children = [
  {childId: 1, name: 'name1'},
  {childId: 2, name: 'name2'},
  {childId: 3, name: 'name3'},
];
const grandChildren = [
  {grandChildId: 1, name: 'name1'},
  {grandChildId: 2, name: 'name2'},
  {grandChildId: 3, name: 'name3'},
];

function getParents(): Observable<Parent[]> {
  return of(parents).pipe(delay(10));
}
function getChildren(parent: Parent): Observable<Child[]> {
  return (parent.id === 1 ? of(children) : of([])).pipe(
    delay(100)
  );
}
function getGrandChildren(child: Child): Observable<GrandChild[]> {
  return (child.childId === 1 ? of(grandChildren) : of([])).pipe(delay(1000));
}
0 голосов
/ 08 ноября 2018

HttpClient вернет Observable<any> данные, поэтому вы не можете просто прочитать данные с помощью оператора map и пытаетесь перебрать Observable<any>

Чтобы получить данные из этой функции - this.getData() вам необходимо получить доступ к ним из класса компонентов, например this.getData().subscribe((res) => {console.log(res)}), теперь вы можете просматривать данные в консоли

Так что теперь переберите массив и вызовите другую сервисную функцию - убедитесь, что у вас есть отдельная функция для всех parent children и grandChildren, или у вас есть общая функция http.get() и передайте URL-адрес на получить данные - это не лучший способ иметь вложенные HttpClient вызовы

Надеюсь, вы поняли - счастливое кодирование

0 голосов
/ 08 ноября 2018

Вы можете сделать что-то вроде этого:

 getRoot() {
    return this.http.get<Parent[]>(baseUrl + 'parent', {withCredentials: true}).pipe(
      switchMap(items => forkJoin(items.map(i => this.getChild(i))))
    )
  }

  getChild(parent) {
    return this.http.get<Children[]>(baseUrl + `parent/${parent.id}/children`, {withCredentials: true}).pipe(
      switchMap(items => forkJoin(items.map(i => this.getGrandChild(i)))),
      map(resp => (parent.children = resp, parent))
    );

  }

  getGrandChild(parent) {
    return this.http.get<GrandChild[]>(baseUrl + `children/${child.id}/GrandChildren`, {withCredentials: true}).pipe(
      map(resp => (parent.grandChildren = resp, parent))
    )
  }

Использует items.map для преобразования массива результатов в массив запросов для соответствующих потомков.

Затем он использует forkJoin, чтобы объединить все эти запросы в 1 Observable

Затем он использует switchMap для выполнения запросов и map для добавления дочерних элементов в ответ.

Вот Stackblitz для демонстрации

0 голосов
/ 08 ноября 2018

возможно ли, что вы путаете прописные и строчные буквы? Используйте условные обозначения, чтобы распознавать что-либо.

Хорошо попробуй parent.children

...