Reputation: 39
I have to make multiply sync webcalls, one after another if it's status is ok.
Horrible, but working code:
this.api.post1().subscribe((data: any) => {
if (data.status== 'OK') {
this.api.post2().subscribe((data: any) => {
if (data.status== 'OK') {
this.api.post3().subscribe((data: any) => {
if (data.status== 'OK') {
this.api.post4().subscribe((data: any) => {
if (data.status == 'OK') {
// Do something
}else{
console.log('error: ' + data.status);
}
});
}else{
console.log('error: ' + data.status);
}
});
}else{
console.log('error: ' + data.status);
}
});
}else{
console.log('error: ' + data.status);
}
});
I try use concatMap
const post1$ = this.api.post1();
const post2$ = this.api.post2();
const post3$ = this.api.post3();
const post4$ = this.api.post4();
from([post1$, post2$, post3$, post4$]).pipe(
concatMap(a => a)
).subscribe(res => console.log(res));
But I need to check is each answer ok here. Is there a beautiful solution to this?
Upvotes: 1
Views: 319
Reputation: 42516
I would recommend you to use RxJS's pipeable operators, and handling the errors along the pipe chain. You can make use switchMap for the chaining of the requests, as well as using throwError to end the chain and emit error observables.
this.api.post1()
.pipe(
switchMap(res => {
if (data.status === 'OK') {
return of(this.api.post2());
} else {
console.log('error: ' + data.status);
return throwError('Twos are bad');
}
}),
switchMap(res => {
if (data.status === 'OK') {
return of(this.api.post3());
} else {
console.log('error: ' + data.status);
return throwError('Twos are bad');
}
}),
switchMap(res => {
if (data.status === 'OK') {
return of(this.api.post4());
} else {
console.log('error: ' + data.status);
return throwError('Twos are bad');
}
}),
).subscribe(res => {
console.log(res);
// do the rest here
}, error => {
// handle error
})
Upvotes: 2
Reputation: 814
Here is another approach:
import { concat, of } from 'rxjs';
import { delay } from 'rxjs/operators';
var post1$ = of({status: "OK", data: 1});
var post2$ = of({status: "OK", data: 2});
var post3$ = of({status: "!OK", data: 3});
var post4$ = of({status: "OK", data: 4});
var runSubscribe = (
data: {status: string, data: any},
chainStatus: {index: number, hasError: boolean}) => {
if( chainStatus.hasError){
return;
}
chainStatus.index++;
if (data.status !== 'OK') {
console.log('error: ', data.status, data.data);
chainStatus.hasError = true;
return;
}
processData(chainStatus.index, data.data);
}
var processData = (index, data) => {
// you should put your "Success" processing function based on index
// I just randomly delay to up to 1000 msec
const random = Math.random()*1000;
delay(random);
console.log(`${index} success:`, data, random);
}
const status = {
index: -1,
hasError: false
}
console.clear();
concat(post1$, post2$, post3$, post4$).subscribe(
data => runSubscribe(data, status)
);
It will stop on 3-rd observable since its status is not "Ok".
see it here: https://stackblitz.com/edit/typescript-35hdyb
Upvotes: -1
Reputation: 466
You can throw a generic error from your stream if any of them error out like below.
const post1$ = this.api.post1();
const post2$ = this.api.post2();
const post3$ = this.api.post3();
const post4$ = this.api.post4();
concat([post1$, post2$, post3$, post4$]).pipe(
switchMap(data => {
if (data.status !== "OK") {
return throwError("Some error");
}
return of(data);
})
).subscribe(res => console.log(res));
OR: If you need to know something specific about each of the observables, you can use concat but pipe the value through each of the endpoints before you get to the concat.
const handleResponse = (type: string) =>
(responseObs) => responseObs.pipe(
switchMap(data => {
if (data.status !== "OK") {
return throwError("Some error about " + type);
}
return of(data);
})
);
const post1$ = this.api.post1().pipe(handleResponse("Post 1"));
const post2$ = this.api.post2().pipe(handleResponse("Post 2"));
const post3$ = this.api.post3().pipe(handleResponse("Post 3"));
const post4$ = this.api.post4().pipe(handleResponse("Post 4"));
concat([post1$, post2$, post3$, post4$]).subscribe(res => console.log(res));
Upvotes: -1