0

I am trying to get multiple person object from multiple API endpoint.

1st API endpoint returns the names of people. 2nd API endpoint returns person detail information. So I have to do get names first, then loop through each name to get detailed information.

Let's say API's person JSON response will be like: {name:'brad', age:'43'}

I have person.component.ts:

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

}

I have 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;
        });
    })
  );

The problem is I can't return a single Observable<Person[]> and the view is always getting undefined.

Please help!

5
  • Why are you calling multiple API requests using forEach it might throw 503 error and not a good approach, you could fetch all details of persons and then you can find person from it by its name. Commented Sep 16, 2020 at 19:31
  • @KamranKhatti Above is an example I need to do in that order. Commented Sep 16, 2020 at 19:37
  • Even the example is wrong, what you need to do fetch all details and then loop through those details array and filter out with person names. Commented Sep 16, 2020 at 19:54
  • @KamranKhatti I think you misunderstood. You have to provide a person's name to get the detail. The above example is indicating that you have to get all names first so you can provide a name to its API to get the detailed information. Like you have to provide product_id to get the product's detailed information. Commented Sep 16, 2020 at 20:05
  • If its for getting only single name record then its fine, what confuse me is getting all names and then getting all details of each name through iteration at once. Commented Sep 16, 2020 at 20:11

1 Answer 1

2

You want to use the mergeMap and forkJoin operators from RxJS to do this:

  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))),
      ));
  }

Edit: persons.map((person) => this.http.get<Person>('/person-detail/v2/' + person.name)) turns the array of persons that was returned from the first http request into an array of Observables. Each Observable represents a call for one name to the person-detail endpoint.

forkJoin turns this Array of Observables into an Observable that emits the array of persons once all calls to person-detail have completed.

mergeMap merges this result Array into the outer Observable such that our function returns an Observable<Person>.

Sign up to request clarification or add additional context in comments.

5 Comments

could you provide an explanation of what mergeMap and forkJoin are doing here?
This code guides me better. But I get an error persons.map is not a function. I have imported 'map' though. import { map, mergeMap, switchMap } from 'rxjs/operators'
persons is supposed to be an array. If it is it will have a .map method. Put a tap(console.log) before the mergeMap in the pipe to find our what you actually have (clearly not an array).
Thanks! this saved me, and I learned a lot from this!
@Wilgert Do you know how to fix this issue I have ? Type 'Observable<unknown[]>' is not assignable to type 'Observable<Person[]>'. Type 'unknown[]' is not assignable to type 'Person[]'. It raises a compile error. I tried many things but no luck yet..

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.