JoshJoe
JoshJoe

Reputation: 1630

How do I return an error from a Meteor.call method inside another Meteor.call

My meteor code goes a couple Meteor.call methods deep at some points. If I have an error in the 2nd layer and I want to throw that meteor error back to the client side how can I do that?

Currently I have something like this, but I'm getting very confusing outputs and I don't think I fully understand what is happening when I'm calling throw new Meteor.Error(500, e.category_code, e.description);

In client.js

Meteor.call('firstCall', data, function (error, result) {
  if(result) {
    doSomething();
  }
  else{
    console.log(error);//just shows 500
  }
});

In server.js

var Future = Meteor.npmRequire("fibers/future");

function extractFromPromise(promise) {
    var fut = new Future();
    promise.then(function (result) {
        fut.return(result);
    }, function (error) {
        console.log(error);
        fut.throw(error);
    });
    return fut.wait();
}

firstCall: function (data){
  try{
    Meteor.call('secondCall', data, 'http://testhref.com/test', 'http://testhref2.com/test' function (error, result) {
      return result;
    });
  }
  catch(e){
    throw new Meteor.Error(500, e.category_code, e.description);
  }
}

secondCall: function (data, paymentHref, otherHref){
  try{
    var associate = extractFromPromise(balanced.get(paymentHref).associate_to_customer(otherHref).debit({
                "amount": data.paymentInformation[0].total_amount * 100,
                "appears_on_statement_as": "Trash Mountain"}));
  }
  catch(e){
    Collection.update(data.id, {
        $set: {
            'failed.category_code': e.category_code,
            'failed.description': e.description
        }
    });
    throw new Meteor.Error(500, e.category_code, e.description);
  }
}

Upvotes: 5

Views: 3405

Answers (2)

Andrew Mao
Andrew Mao

Reputation: 36900

In your case, the catch in firstCall is not going to have anything defined for e.category_code and e.description when secondCall throws. This is because in secondCall you are passing these two as arguments to Meteor.Error, which takes as its arguments error, reason, and details:

https://github.com/meteor/meteor/blob/devel/packages/meteor/errors.js

In order to pass these through, you will need to amend firstCall to use these properties:

firstCall: function (data){
  try{
    Meteor.call('secondCall', data, 'http://testhref.com/test', 'http://testhref2.com/test');
  }
  catch(e){
    throw new Meteor.Error(500, e.reason, e.details);
  }
}

I'm not even sure you need to split it up into two calls for modularity, as you can just use normal Javascript functions. But we can discuss that elsewhere.

Upvotes: 2

Tomas Romero
Tomas Romero

Reputation: 8698

I few things to mention here:

  1. Async function don't throw exceptions (except you make them kind of sync using Meteor._wrapAsync as I will explain later), they return the error on another way (as the first argument in NodeJS callback-style). This applies both for Meteor.call and to your doSomeAsyncThing.
  2. I can't see the benefit of using Meteor.call on the server. Meteor.call is meant to call server methods from the client. In this case you could just call YourObj.secondCall from inside of firstCall.
  3. Returning something from inside of a callback (as you are doing inside firstCall) doesn't have any effect. You want your async code to work as sync code, so I suggest using Meteor._wrapAsync which is very well explained here. So, I would implement server side a bit different:
firstCall: function (data){
  try{
    return this.secondCall(data);
  }
  catch(e){
    throw new Meteor.Error(500, e.category_code, e.description);
  }

secondCall: function (data){
  try{
    return Meteor._wrapAsync(doSomeAsyncThing)(data);
  }
  catch(e){
    Collection.update(data.id, {
        $set: {
            'failed.category_code': e.category_code,
            'failed.description': e.description
        }
    });
    throw new Meteor.Error(500, e.category_code, e.description);
  }

Hope this helps!

Upvotes: 0

Related Questions