title: Angular combining parallel and chained requests with $http.then() and $q.all()
body: <p>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 <code>$http</code> service to chain requests, and how to use the <code>$q</code> service to make requests in parallel. But for this specific API workflow I need to do both.</p>
  
  <p>Here is an example of the high-level API flow:</p>
  
  <ul>
  <li><code>/dog/&lt;dog_id&gt;</code>
  <ul>
  <li><code>/breed/&lt;breed_id&gt;</code>
  <ul>
  <li><code>/food/&lt;food_id&gt;</code></li>
  </ul></li>
  </ul></li>
  <li><code>/cat/&lt;cat_id&gt;</code></li>
  <li><code>/turkey/&lt;turkey_id&gt;</code></li>
  <li><code>/fish/&lt;fish_id&gt;</code></li>
  </ul>
  
  <p>The first tier of requests all have known ids. However the <code>&lt;breed_id&gt;</code> required to make the <code>/breed</code> call must be parsed from the <code>/dog</code> response, and the <code>&lt;food_id&gt;</code> required to make the <code>/food</code> call must be parsed from the <code>/breed</code> response. So <code>/dog</code>, <code>/breed</code>, and <code>/food</code> all need to be chained. However <code>/cat</code>, <code>/turkey</code>, and <code>/fish</code> can be made in parallel with the entire <code>/dog</code> chain.</p>
  
  <p>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 <code>.then()</code>?</p>
  
  <pre><code>var dogId = '472053',
      catId = '840385',
      turkeyId = '240987',
      fishId = '510412';
  
  var myData = {};
  
  var firstSetComplete = false,
      secondSetComplete = false,
      returnData = function() {
          if (firstSetComplete &amp;&amp; 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();
  });
  </code></pre>