0

I am not able to get the error in client's Meteor.call error callback when in the server code, an error occurs inside Meteor.bindEnvironment. Below is example code to replicate

In the server

Meteor.methods({
  customMethod: function(arg1, arg2){
      Stripe.customers.create({
        email: "email@here.com,
        description: "blah blah",
        source: token,
        metadata: {
          planId: planId,
          quantity: n
        },
        plan: planId,
        quantity: n
      }, Meteor.bindEnvironment(function (err, customer) {
        if(err){
          console.log("error", err);
          // TODO cannot catch this error on the client
          throw new Meteor.Error(err.rawType, err.message)
        }
      }))
    }
})

In the client inside a Meteor event,

Meteor.call('customMethod', arg1, arg2, function (err, resp) {
 if(err){
   Session.set('some-error', err)
 }
 if(resp){
   // TODO cannot catch errors throwing from the server
   // when inside Meteor.bindEnvironment 
   Session.set('some-success', true)
 }
});

The session variables are never set. Any help would be great. Thanks!

Pramodh
  • 775
  • 2
  • 9
  • 17

1 Answers1

0

The second argument to Meteor.bindEnvironment is an error-handler that gets called whenever an exception is thrown within the callback you supplied as the first argument. So you can do something like this to get the error passed back to the client:

Meteor.bindEnvironment(function (err, customer) {
  if (err) throw err
  ...
}, function (err) {
  if (err) throw new Meteor.Error(err.message)
})

UPDATE

Apologies, that was a bit hasty. The problem is the fact that your error (and potentially results) are coming from an asynchronous callback, so your method function will have finished executing, and implicitly returned undefined (which gets passed to the client as null) by the time the callback does anything.

Historically, you'd resolve this with a future, but now we have promises, which are better:

Meteor.methods({
  customMethod (arg1, arg2) {
    return new Promise((resolve, reject) => {
      Stripe.customers.create({
        email: "email@here.com,
        ...
      }, Meteor.bindEnvironment(function (err, customer) {
        if(err){
          reject(err)
        }
        resolve(customer)
      })).catch(e => { throw new Meteor.Error(e) })
  }
})

Meteor methods are clever enough to wait for promises to resolve or reject and return the result (or error) via DDP. You still need to catch the error and formally throw it, but your method call will wait for you to do so.

richsilv
  • 7,993
  • 1
  • 23
  • 29
  • it throws the error, the app exits with code 8 and restarts. its not going to the error handler. – Pramodh Nov 20 '15 at 19:10
  • I had to modify this to get it to work!! But thanks a ton!! var promise = new Promise( function(resolve, reject){ Stripe.customers.create({ email: "email@here.com, ... }, Meteor.bindEnvironment(function (err, customer) { if(err){ reject(err) } resolve(customer) })).catch(e => { throw new Meteor.Error(e) }) return Promise.await(promise); – Pramodh Nov 25 '15 at 15:16
  • Are you using Meteor 1.2? If not, just `meteor add ecmascript` and you can use arrow functions. – richsilv Nov 25 '15 at 15:17
  • 1
    if you add the in-house ecmascript package, you don't need the okgrow package and you can use (almost) all the features of ES2015. – richsilv Nov 25 '15 at 15:43