1

I'm fairly new to Promises and have been attempting to get this piece of code to work properly. Here's what I have.

var Promise = require('bluebird');

    Promise.join(getProducts, getPricing, function(products, pricing) {
            console.log('products: ' + products.body);
            console.log('pricing: ' + pricing.body);

            // Add pricing to products here

            res.send(products.body);
        })
        .catch(function(e) {
            console.log(e);
            res.sendStatus(500);
        });

Requirements...

  • I want to call both APIs at the exact same time and process the results when both complete.
  • If the Pricing API fails, I still want to return the Products with no pricing.
  • If the Products API fails, I want to error out and send 500 back to the client.

My code seems to work if both API calls are successful, but will always go into the catch if either fail and ignore any successful calls.

I can get this working fine if I use a synchronous Promise chain, but I'd like to call both APIs at the same time.

How can I call both APIs asynchronously and process the results outside of the catch?

lionpants
  • 1,469
  • 14
  • 24

3 Answers3

2

You'll want to put a catch on exactly the promise whose failure you want to handle - i.e. getPricing.

Promise.join(getProducts, getPricing.catch(function(err) {
    // ignore or log?
    return null;
}, function(products, pricing) {

    console.log('products: ' + products.body);
    if (pricing) {
        console.log('pricing: ' + pricing.body);
        // Add pricing to products here
    } // else?
    res.send(products.body);
}).catch(function(e) {
    console.log(e);
    res.sendStatus(500);
});

You can also use getPricing.reflect() if you want to more explicitly distinguish the two cases.

Bergi
  • 630,263
  • 148
  • 957
  • 1,375
  • Fantastic, didn't realize catching on a specific Promise will skip the Global catch if the error has already been caught! Exactly what I needed, thanks. – lionpants Nov 05 '15 at 19:26
  • Yes, [`catch` does *handle* the error](http://stackoverflow.com/questions/16371129/chained-promises-not-passing-on-rejection) :-) – Bergi Nov 05 '15 at 19:28
1

Forewarning: I'm decent with promises, but not this particular library.

var Promise = require('bluebird');

var pricing = getPricing().catch(function(e) {
  return null;
})

Promise.join(getProducts, pricing, function(products, pricing) {
        console.log('products: ' + products.body);
        console.log('pricing: ' + pricing ? pricing.body : '<null>');

        // Add pricing to products here

        res.send(products.body);
}).catch(function(e) {
  console.log(e);
  res.sendStatus(500);
});
Katana314
  • 8,429
  • 2
  • 28
  • 36
  • Why did you move the final `catch`? Now it'll report an unhandled rejection. – Bergi Nov 05 '15 at 19:13
  • It was moved so that it would exclusively catch a `products` failure (if products fails but pricing takes over a minute, you can fail early), but I realize you're right about the unhandled rejection part. – Katana314 Nov 05 '15 at 19:19
  • 1
    `Promise.join` does fail early anyway – Bergi Nov 05 '15 at 19:20
  • Yeah, good catch. I've made some edits - we essentially have the same answer now. – Katana314 Nov 05 '15 at 19:21
  • Thanks Katana! I read and chose the other answer first though, luck of the draw I guess. :) – lionpants Nov 05 '15 at 19:28
1

Modify getPricing() such that it never fails. The easiest way to do this is by adding a top-level .catch(). The example code below wraps the getPricing() method

var Promise = require('bluebird');

function getProducts(){/* add implementation */};

function originalGetPricing(){/* add implementation */};

function getPricing(){
   return originalGetPricing()
     .catch(function(err) {
       return Promise.resolve(/* replace this comment with empty object or some other suitable response */);
     });
};

Promise.join(getProducts, getPricing, function(products, pricing) {
        console.log('products: ' + products.body);
        console.log('pricing: ' + pricing.body);

        // Add pricing to products here

        res.send(products.body);
    })
    .catch(function(e) {
        console.log(e);
        res.sendStatus(500);
    });
Jared Dykstra
  • 3,596
  • 1
  • 13
  • 25