I have a rather complicated set of API calls to make and I'm attempting to do it as elegantly and performant as possible. I understand how to use the promise api of the $http
service to chain requests, and how to use the $q
service to make requests in parallel. But for this specific API workflow I need to do both.
Here is an example of the high-level API flow:
/dog/<dog_id>
/breed/<breed_id>
/food/<food_id>
/cat/<cat_id>
/turkey/<turkey_id>
/fish/<fish_id>
The first tier of requests all have known ids. However the <breed_id>
required to make the /breed
call must be parsed from the /dog
response, and the <food_id>
required to make the /food
call must be parsed from the /breed
response. So /dog
, /breed
, and /food
all need to be chained. However /cat
, /turkey
, and /fish
can be made in parallel with the entire /dog
chain.
What I've got now (and it is working fine) are two separate sets of requests. How do I improve on this flow? Is there a way to combine the two stacks in a way that results in a single promise execution of .then()
?
var dogId = '472053',
catId = '840385',
turkeyId = '240987',
fishId = '510412';
var myData = {};
var firstSetComplete = false,
secondSetComplete = false,
returnData = function() {
if (firstSetComplete && secondSetComplete) {
console.log("myData.dog", myData.dog);
console.log("myData.dog.breed", myData.dog.breed);
console.log("myData.dog.food", myData.dog.food);
console.log("myData.cat", myData.cat);
console.log("myData.turkey", myData.turkey);
console.log("myData.fish", myData.fish);
}
};
// first call set
$http.get('http://example.com/dog/' + dogId)
.then(function(response) {
myData.dog = response.data;
return $http.get('http://example.com/breed/' + response.data.breed_id);
})
.then(function(response) {
myData.dog.breed = response.data;
return $http.get('http://example.com/food/' + response.data.food_id);
})
.then(function(response) {
myData.dog.food = response.data;
firstSetComplete = true;
returnData();
});
// second call set
$q.all([
$http.get('http://example.com/cat/' + catId),
$http.get('http://example.com/turkey/' + turkeyId),
$http.get('http://example.com/fish/' + fishId)
])
.then(function(responses) {
myData.cat = responses[0].data;
myData.turkey = responses[1].data;
myData.fish = responses[2].data;
secondSetComplete = true;
returnData();
});
You can pass in the first chain like so:
$q.all([
$http.get('http://example.com/cat/' + catId),
$http.get('http://example.com/turkey/' + turkeyId),
$http.get('http://example.com/fish/' + fishId),
$http.get('http://example.com/dog/' + dogId)
.then(function(response) {
myData.dog = response.data;
return $http.get('http://example.com/breed/' + response.data.breed_id);
})
.then(function(response) {
myData.dog.breed = response.data;
return $http.get('http://example.com/food/' + response.data.food_id);
})
.then(function(response) {
myData.dog.food = response.data;
return myData;
})
])
.then(function(responses) {
myData.cat = responses[0].data;
myData.turkey = responses[1].data;
myData.fish = responses[2].data;
secondSetComplete = true;
returnData();
});
That big chain of promises for dogs ends up returning a single promise that is resolved when the last then
is called and it's resolved with the result from that final function. So there is no reason that you can't nest it in your $q.all()
call.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With