I am facing a challenge where I need to merge the outcomes of various http calls into a single Observable. These calls must be executed sequentially, with each call waiting for the previous one to finish. The catch is that the number of http calls needed is not known until runtime.
While I have come across similar queries before, they always had a fixed number of initial calls, making it easy to manage them using nested or chained pipe operations. In my case, however, I need to handle anywhere from 0 to n API calls.
My initial thought is to use concatMap()
, but I am not entirely sure and couldn't quite grasp the syntax required to implement it successfully.
// Submit all phones to the API individually and return the updated results in a single array.
savePhones(phones: Phone[]): Observable<Phone[]> {
let updatedPhones: Phone[] = [];
if (phones.length === 0) {
return of<Phone[]>(updatedPhones);
}
// I need a solution like this but for handling multiple phones.
// Add each Observable result to the array after completion.
// Begin the next Observable only after the previous one finishes.
// Finally, return the Observable array once all are done.
return this.postPhone(contactId, phones[0])
.pipe(
map(response1 => {
let p1 = new Phone();
p1.loadFromJson(response1);
updatedPhones.push(p1);
}),
concatMap(() => this.postPhone(contactId, phones[1])
.pipe(map(response2 => {
let p2 = new Phone();
p2.loadFromJson(response2);
updatedPhones.push(p2);
}))),
concatMap(() => this.postPhone(contactId, phones[2])
.pipe(map(response3 => {
let p3 = new Phone();
p3.loadFromJson(response3);
updatedPhones.push(p3);
}))),
map(() => {
return updatedPhones;
})
);
}
private postPhone(
contactId: string,
phone: Phone): Observable<Phone> {
let criteria = phone.toJson();
let url = phone.isNew()
? `${apiUrl}/contacts/${contactId}/phones/add`
: `${apiUrl}/contacts/${contactId}/phones/${phone.phoneId}/update`;
return this.httpClient.post(url, criteria));
}
Your insight would be greatly appreciated.