I want to chain calls to different libraries using promises. In case of failure, library methods return an object describing the error, but with different fields depending the library.
In order to report any error consistently to the callee, I would like to normalize all error objects to follow a common format. But I have no idea how to do that in an elegant way using Bluebird and/or the standard promise API.
In pseudo-js here is what I have :
var methodAFromLibX_Async = Promise.promisify(...);
var methodBFromLibY_Async = Promise.promisify(...);
methodAFromLibX_Async(...)
.then(function(result) {
methodBFromLibY_Async(...)
.then(function(result) { ... })
.catch(normalizeAndSendErrorFromLibY);
})
.catch(normalizeAndSendErrorFromLibX);
The above code seems to work, but :
- I have redundant code between
normalizeAndSendErrorFromLibY
andnormalizeAndSendErrorFromLibX
- I my real use case I have to chain more than 2 calls, and the pyramid shape of the code definitely starts looking like a callback hell...
EDIT: In order to be a little more clear, here the solution I envision, but can't achieve :
You could use bluebird filtered catch: http://bluebirdjs.com/docs/api/catch.html#filtered-catch
And change your code to something like this:
The solution you are looking for is
But this is pretty ugly. Given that your error handlers rethrow the error anyway, you might also use
which still isn't optimal. You don't want to put a
.catch(normalise)
on every call to these functions, and you don't want to be forced to nest them. So better factor each of them in their own function:You might combine that with the promisification of the library methods.
If you want to avoid the pattern you are demonstrating in your example there seem to be two other options for you:
You
promisify
your libraries as shown, propagate errors properly in your chain and then build one function that is able to normalize all known errors:The other option would be to manually promisify your library methods and normalize the errors here:
Reading your latest comment I guess the latter might fit your needs better.
As an alternate solution, using Bluebird's Promise.coroutine: