Trying to wrap my head around Observables and chaining / nesting HTTP requests.
Let's say I have the following REST endpoints from my dog-walking API back-end, which cannot be changed:
GET /dogs(returns all dogs):[ { id: 1, name: 'Fido' }, { id: 2, name: 'Barky' }, { id: 3, name: 'Chip' }, { id: 4, name: 'Bracken' } ]GET /walker/:id(returns a single dog walker):{ id: 1, name: 'John Doe' }GET /pairings(returns all pairings between dogs and walkers):[ { id: 1, dogIds: [2], walkerId: 1 }, { id: 2, dogIds: [1, 3], walkerId: 2 } ]
Business rules
- A pairing has exactly 1 walker
- A pairing has a list of 1 or more dogs
- A dog can be part of 0 or 1 pairings
- A walker can be part of 0 or 1 pairings
Objective
I want to present a list of all pairings between walkers and dogs, sorted by walker name. I want to sub-sort each walker's dogs by name. I don't want to show any walkers or dogs without an active pairing, e.g:
Walker | Dogs
-------------+-----------
John Doe | Barky
Jan Kowalksi | Chip, Fido
My thought process
- Request all
/pairingsand/dogsin parallel - Wait for both of those requests to complete
- Loop over each
pairingand populate thedogsfield - Pluck the
walkerIdfrom eachpairingand request each/walker/:idin parallel - Wait for all of those requests to complete
- Loop over each
pairingand populate thewalkerfield
I feel like I could do this quite easily using Promises but I'm struggling to adapt my brain to thinking in Observables. Here's what I've got so far (using Angular's HttpClient):
function getDogWalkerPairings() {
return Observable.forkJoin([
this.http.get('/pairings'),
this.http.get('/dogs')
])
.map(
(res) => {
const pairings = res[0];
const dogs = res[1];
return pairings.map(p => {
const pDogs = p.dogIds.map(dogId =>
dogs.find(d => (d.id === dogId)
);
return Object.assign({ dogs: pDogs }, p);
});
}
)
.map((pairingsWithDogs) => {
return Observable.forkJoin(
pairingsWithDogs.map(p => this.http.get('/walkers/' + p.walkerId))
);
})
.map((walkers) => {
// uhhh... where to now?
// I don't have a reference to pairings in this scope :/
});
}