For the sake of the example lets say I have a entity called client:
interface Client {
id: number
name: string
address: Address[]
}
interface Address {
id: number
street: string
}
In this case I cannot update the name
of client and his addresses
in the same call.
Instead I need to:
So what I want to do is join this multiple http calls that can happen conditionally in one observable.
This is what I have so far:
updateClientAndClientAddresses(): Observable<Client> {
return of({}).pipe(
******* Conditionally make all the create addresses calls *******
******* Conditionally make all the update addresses calls *******
******* Then make the update name call *******
switchMap(([updateNameResponse: Client, responseOfAllAddressesToBeCreated: Address, responseOfAllAddressesToUpdated: Address]) => {
// Ideally here I will have the results of all the calls made so far.
// Merge everything manually here
return {
...updateClientCallResponse,
addresses: [
...responseOfAllAddressesToBeCreated,
...responseOfAllAddressesToUpdated
]};
}),
)
}
Just to reinforce: Before I do the call to update the name I need to check if:
addressesToBeCreated.length
if yes I need to do one particular call for every lenght of this array, wait for the response and store the result to be used latter on.then I need to check if:
addressesToUpdated.length
if yes I need to do another particular call vor every lenght of this array and wait for the response and store the result to be used latter on.
Finally I will do the call to update the name od the client, get the result and then merge with all the responses that I conditionally made before.
Organize addresses into two groups: those to be created, and those to be updated.
const addressesToBeCreated: Address[] = [ /* list of addresses to be created */ ];
const addressesToBeUpdated: Address[] = [ /* list of addresses to be updated */ ];
Collect the HTTP requests needed to create and update the addresses, respectively. (Assumptions were made with what the server response content will be.)
const createRequests: Observable<Address>[] = addressesToBeCreated.map(
(address) => this.client.post(...) // 👈 request server to save the address, and respond with the created address resource
);
const updateRequests: Observable<Address>[] = addressesToBeUpdated.map(
(address) => this.client.put(...) // 👈 request server to update existing address, and respond with the updated address resource
);
Construct a pipeline using operators forkJoin
and concatMap
, in a way that tells RxJS to actually trigger sending the create and update requests, and then return said addresses that were created and updated.
const savedAddresses$ = forkJoin(createRequests) // 👈 trigger the bunch of HTTP requests that creates addresses
.pipe(
concatMap((createdAddresses) => { // 👈 now we have a list of created addresses
return forkJoin(updateRequests) // 👈 next, trigger HTTP requests that updates addresses
.pipe(
map((updatedAddresses) => { // 👈 now we have the list of updated addresses
return [ // 👈 emit a tuple of created and updated addresses down the pipeline
createdAddresses,
updatedAddresses
];
})
);
})
);
savedAddresses$
will be an observable that emits an array of two elements: a list of created addresses, and list of updated addresses.
Finally do another call to change the name of the client.
const savedModels$ = savedAddresses$.pipe(
concatMap((savedAddresses) => {
return this.client.put(...) // 👈 request server to update client name, and return updated client model
.pipe(
map((updatedClient) => { // 👈 now we have the client object with updated name
return [updatedClient, ...savedAddresses]; // 👈 emit a tuple down the pipeline with three elements: client, list of created addresses, and list of updated addresses
})
);
})
);
savedModels$
will be an observable that emits an array of three elements: client model with its name updated, list of addresses created, and list of addresses updated.
At this point, you can finally "merge everything manually here." You can join data about the client, and addresses that have been created and updated however you like.
updateClientAndClientAddresses(): Observable<Client> {
... // 👈 code from previous steps
return savedModels$.pipe(
map(([updatedClient, createdAddresses, updatedAddresses]) => {
return {
...updatedClient,
address: [
...createdAddresses,
...updatedAddresses
]
};
})
);
}