Несколько HTTP-запросов на Rest API - PullRequest
0 голосов
/ 11 июня 2019

Я написал функцию, которая получает наблюдаемый список покемонов из API pokeapi.co. Если я хочу использовать эту функцию (getPokemons ()), мне нужно подписаться на нее. Однако ответ на подписку возвращает пустой список, потому что в моей функции я выполняю еще один вызов API, используя функцию подписки.

Интернет пояснил, что подписка в запросе http является распространенной ошибкой и что вам нужно использовать forkMap, flatMap, switchMap, mergeMap или что-то еще. К сожалению, я не понимаю, как я могу применить одну из этих функций к моему делу.

getPokemons(pageNumber: number) : Observable<Pokemon[]> {
    var apiUrl = `${this.apiRoot}?&limit=${this.itemCount}&offset=${pageNumber * this.itemCount - (20)}`;
    return this.httpClient.get<any>(`${apiUrl}`).pipe(
      map(res => {
        var results: Pokemon[] = [];
        for (let pokemon of res.results) {
          this.getPokemonByName(pokemon.name).subscribe(data => {
            results.push(data);
          },
          err =>  {
            console.error(err.error || 'API error');
          });
        }
        return results;
      })
    );
  }

getPokemonByName(name: string) : Observable<Pokemon> {
    return this.httpClient.get<Pokemon>(`${this.apiRoot}/${name}`).pipe(
      map(res => {
        return new Pokemon(res);
      })
    );
  }

В моем сценарии оригинальный http.get () отвечает списком, в котором есть только имя покемона. Мне нужно сделать еще один вызов API, чтобы получить информацию о конкретном покемоне. Поскольку getPokemonByName (). Subscribe () является асинхронным, массив «results» остается пустым.

Я надеюсь, что вы понимаете мою проблему, и вы можете помочь мне понять, как решить эту проблему.

Ответы [ 2 ]

1 голос
/ 11 июня 2019

вы можете использовать forkJoin вот так -

getPokemons(pageNumber: number) : Observable<Pokemon[]> {
    var apiUrl = `${this.apiRoot}?&limit=${this.itemCount}&offset=${pageNumber * this.itemCount - (20)}`;
    return this.httpClient.get<any>(`${apiUrl}`)
               .pipe(
                      switchMap(res => {

                        //now you want to call getPokemonByName for each of the result your got in res.results
                        //so first create an array from getPokemonByName -
                        const observables$ = res.result.map(pokemon => this.getPokemonByName(pokemon.name));
                        return forkJoin(observables$);                        
                      })
                    );
  }

  getPokemonByName(name: string) : Observable<Pokemon> {
    return this.httpClient.get<Pokemon>(`${this.apiRoot}/${name}`).pipe(
      map(res => {
        return new Pokemon(res);
      })
    );
  }
}

Теперь ваш потребитель getPokemons должен подписаться на наблюдаемое, возвращаемое getPokemons.

1 голос
/ 11 июня 2019

Вы действительно можете упростить свой метод getPokemons() с помощью операторов RxJS, таких как forkJoin . forkJoin() будет выполнять цикл for..of перед возвратом всех наблюдаемых. Если вы знакомы с использованием Promises в JavaScript, на самом деле это похоже на Promise.all.

Как только вы подпишетесь на него, вы сможете получить возвращаемые значения. И не забудьте импортировать нужные вам операторы в ваш компонент!

import { forkJoin } from 'rxjs';
.
.
getPokemons(pageNumber: number): Observable < Pokemon[] > {
  const apiUrl = `${this.apiRoot}?&limit=${this.itemCount}&offset=${pageNumber * this.itemCount - (20)}`;
  const observablesList = [];

  return this.httpClient.get<any>(`${apiUrl}`).pipe(
    map(res => {
      const observablesList = [];
      for (let pokemon of res.results) {
        observablesList.push(this.getPokemonByName(pokemon.name));
      }
      return forkJoin(observablesList);
    })
  ).subscribe(res => {
    console.log(res);
    // do the rest here
  })
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...