Reputation: 4704
I have to make an API call (returns Promise
) after another API call (returns Observable
).
The userService.getAuthUser()
returns an Observable
.
The userService.updateUser()
returns a Promise
.
I can achieve that by putting updateUser()
inside getAuthUser()
this.userService.getAuthUser().subscribe((res) =>{
this.userService.updateUser(res.id, <User>({
name: 'Sample Name'
})).then((res) =>{
console.log('update user success');
}).catch((err) => {
console.log('update user failed');
})
},
(err) => {
console.log('get auth user failed');
})
But i feel that is not very good doing this way, kind of callback hell, any better way to do so?
Note: I can't change userService.updateUser()
to Observable
.
Upvotes: 6
Views: 9497
Reputation:
There are a few ways you can achieve this.
One way if you want the getAuthUser stream to remain active is to transform the promise to an observable with the from operator. This will allow you to continue the stream and react to errors/handle success for the entire stream. You can also specify where in the stream to react to specific errors with the catchError operator.
Something similar to:
this.userService.getAuthUser()
.pipe(
catchError(err => {
// throw an error how you like, see the 'throw' operator
// can also create with other operators like 'of'
}),
switchMap(auth =>
from( // will detect promise and return observable
this.userService.updateUser(res.id, <User>({
name: 'Sample Name'
}))
)
),
catchError(err => {
// throw an error how you like, see the 'throw' operator
// can also create with other operators like 'of'
})
).subscribe(
(res) => {
// if you were expecting data at this point
}, (err) => {
// if you threw the error
}
)
Another way if you don't need the stream to remain active, you can convert the Observable from the first stream to a Promise with .toPromise()
. From here, you have two typical paths to follow. You can use async/await, or just chain the promises.
For the async await, something similar to:
// the method will have to be async for await to not show errors
const authUser = await this.userService.getAuthUser().toPromise();
// determine if you should update
// if so
const updateUserResult = await this.userService.updateUser(res.id, <User>({name: 'Sample Name'}));
Upvotes: 11
Reputation: 2692
import { flatMap, map, catchError } from 'rxjs/operators';
import { of, from } from 'rxjs';
this.userService
.getAuthUser()
.pipe(
flatMap(
({ id }) =>
from(this.userService.updateUser(id)).pipe(
map(response => {
console.log('update user success');
return response;
}),
catchError(error => {
console.log('update user failed');
return of(error);
})
),
catchError(error => {
console.log('get auth user failed');
return of(error);
})
)
)
.subscribe();
Upvotes: 3