So,I'm in kind of fix here. I've got 2 GET APIs. I need to do something once those APIs return success.
I did the following.
let sub1$ = this.myService.callFirstApi();
let sub2$ = this.myService.callSecondApi();
forkJoin([sub1$,sub2$]).subscribe(() => executeRestCodeNow());
The above works fine but in my project, devs are subscribing to APIs and then working on the data from the APIs in individual functions, example:
myService.ts:
firstApi(){
return this.http.get(apiurl).pipe(map(res) => res);
}
secondApi(){
return this.http.get(apiurl).pipe(map(res) => res);
}
component.ts File:
ngOnint = () => {
this.getFirstApi();
this.getSecondApi();
}
getFirstApi(){
let sub1$ = this.myService.firstApi().subscribe((data) => doingSomethingWithData)
}
getSecondApi(){
let sub2$ = this.myService.firstApi().subscribe((data) => doingSomethingWithData)
}
Now, how do I combine these 2 separate functions and use forkJoin here? Because if I put them together in one function and use forkJoin like I showed at the beginning then I get an error as
"You provided an invalid object where a stream was expected. You can provide an Observable, Promise, Array, Or Iterable"
I tried returning sub1$ and sub2$ too.
First, to point out ur mistake, assuming the function in your component.ts file looks like this:
getFirstApi(){
let sub1$ = this.myService.firstApi().subscribe((data) => doingSomethingWithData)
return sub1$
}
The sub$
you had returned is an Subscription
not an Observable
. Therefore, when provided in forkJoin
you get that error.
Now, if u want ur Observable
to independently execute some code when it receive data, then execute another when both is done, there is 2 ways I could think of to achieve it.
Option 1
the most common and straight forward option is using the rxjs (tap) operator.
// do not call subscribe in this function
getFirstApi(){
let obs1$ = this.myService.firstApi().pipe(tap((data) => doingSomethingWithData))
return obs1$
}
forkJoin([this.getFirstApi(), this.getSecondApi()])
.subscribe(() => executeRestCodeNow())
or
let sub1$ = this.myService.callFirstApi().pipe(tap((data) => doingSomethingWithData));
let sub2$ = this.myService.callSecondApi().pipe(tap((data) => doingSomethingWithData));
forkJoin([sub1$,sub2$]).subscribe(() => executeRestCodeNow());
Option 2
The second option is slightly complex, and require some understanding of concept of hot and cold observable. I won't explain what is hot/cold observable here, so it is up to u to do your own research.
But to keep the answer short, this option requires to use rxjs (shareReplay) operator.
let sub1$ = this.myService.callFirstApi().pipe(shareReplay(1));
let sub2$ = this.myService.callSecondApi().pipe(shareReplay(1));
sub1$.subscribe((data) => doingSomethingWithData);
sub2$.subscribe((data) => doingSomethingWithData);
// this will not fire duplicate API request
forkJoin([sub1$,sub2$]).subscribe(() => executeRestCodeNow());
Edit: I may have mis-used the term hot/cold observables, not really sure, maybe the more appropriate term to look for in option 2 is Multicasting