Angular observable service возвращает для каждого массива. Необходимо выполнить http-запрос для цикла

#javascript #angular #typescript

#javascript #angular #typescript

Вопрос:

Я пытаюсь получить объект нескольких пользователей из нескольких конечных точек API.

1-я конечная точка API возвращает имена людей. 2-я конечная точка API возвращает подробную информацию о персонаже. Итак, я должен сначала получить имена, а затем выполнить цикл по каждому имени, чтобы получить подробную информацию.

Допустим, ответ API person JSON будет таким: {имя: ‘брэд’, возраст:’43’}

У меня есть person.component.ts:

 getPersons(): void {
 this.personService.getPeople()
 .subscribe(people => this.people = people);
  

}

У меня есть person.service.ts:

 getPeople(): Observable<Person[]> {
return this.http.get<Person[]>(People_Names_API)
  .toPromise()
  .then(names => names ['name']
    .forEach(personName=> {
      const personDetailUrl = '/person-detail/v2/'   personName;
      this.http.get(personDetailUrl )
        .toPromise()
        .then((res: Person) => {
           return res;
        });
    })
  );
  

Проблема в том, что я не могу вернуть ни одного, Observable<Person[]> и представление всегда получает undefined .

Пожалуйста, помогите!

Комментарии:

1. Почему вы вызываете несколько запросов API, используя forEach, это может вызвать ошибку 503, а не хороший подход, вы могли бы получить все сведения о лицах, а затем вы можете найти person из него по его имени.

2. @KamranKhatti Выше приведен пример, который мне нужно выполнить в таком порядке.

3. Даже пример неправильный, то, что вам нужно сделать, извлекает все детали, а затем перебирает массив этих деталей и отфильтровывает имена пользователей.

4. @KamranKhatti Я думаю, вы неправильно поняли. Вы должны указать имя пользователя, чтобы получить подробную информацию. Приведенный выше пример указывает на то, что сначала вам нужно получить все имена, чтобы вы могли предоставить имя его API для получения подробной информации. Например, вы должны указать product_id, чтобы получить подробную информацию о продукте.

5. Если он предназначен для получения только одной записи имени, тогда все в порядке, что меня смущает, так это получение всех имен, а затем одновременное получение всех деталей каждого имени с помощью итерации.

Ответ №1:

Для этого вы хотите использовать операторы mergeMap and forkJoin из RxJS:

   getPeople(): Observable<Person[]> {
    return this.http.get<Person[]>(People_Names_API)
      .pipe(
        mergeMap((persons) => forkJoin(persons.map((person) => this.http.get<Person>('/person-detail/v2/'   person.name))),
      ));
  }
  

Редактировать:
persons.map((person) => this.http.get<Person>('/person-detail/v2/' person.name))
превращает массив лиц, который был возвращен из первого http-запроса, в массив наблюдаемых. Каждый наблюдаемый объект представляет собой вызов для одного имени person-detail конечной точки.

forkJoin превращает этот массив наблюдаемых в наблюдаемый, который выдает массив лиц после завершения всех вызовов person-detail .

mergeMap объединяет этот результирующий массив с внешним наблюдаемым таким образом, что наша функция возвращает Observable<Person> .

Комментарии:

1. не могли бы вы предоставить объяснение того, что здесь делают mergeMap и forkJoin?

2. Этот код помогает мне лучше. Но я получаю сообщение об ошибке persons.map is not a function . Однако я импортировал «карту». import { map, mergeMap, switchMap } from 'rxjs/operators'

3. предполагается, что persons представляет собой массив. Если это так, у него будет метод .map . Поместите a tap(console.log) перед картой слияния в канале, чтобы найти то, что у вас на самом деле есть (явно не массив).

4. Спасибо! это спасло меня, и я многому научился из этого!

5. @Wilgert Вы знаете, как исправить эту проблему, которая у меня есть? Type 'Observable<unknown[]>' is not assignable to type 'Observable<Person[]>'. Type 'unknown[]' is not assignable to type 'Person[]'. Возникает ошибка компиляции. Я много чего перепробовал, но пока безуспешно..