5

I've been working with Meteor and the stripe package to try and make a customer. So First I have my client side code which calls a method on the server so when clicked i have in the client.js:

Meteor.call('usersignup', function (error, result) {
    console.log (result);
});

So this calls the Method on the server.js:

var Future = Npm.require('fibers/future');
var stripe = StripeAPI('my key'); // secret stripe API key

Meteor.methods({

    usersignup: function(cusEmail){
        var fut = new Future();

        stripe.customers.create(
            { email: cusEmail },
            function(err, customer) {
                if (err) {
                    console.log(err);
                    fut.ret;
                }
                fut.ret(customer);
            }
            );
        return fut.wait();
    },

    userfail: function(cusid){
        var fut = new Future();

        stripe.customers.retrieve(cusid, function(err, result) {
            if(err){
                    console.log(err);
                    fut.ret;
                }
                fut.ret(err, result);
            });
        return fut.wait();
    }

});

Now this works and creates a customer when I log onto the stripe.com dashboard but I'm trying to get the response returned to the client well at least the customer id for now and print it in the console. This is where I can't seem to get it to work. It'll log undefined when I do console.log(result). Any ideas?

EDIT: So I put the fiber and the stripe key as global variables now and don't get an error but the returns don't seem to be returning any values. so on the client side I have:

'click #signupsubmit': function (event) {
    console.log("hello");
    var whatis = getVal(); // function gets value of forms and returns object
    var testid;
    var cusid = Meteor.call('usersignup', whatis.email, function (error, result) {
        if (error) {
            console.log(err.message);
            return;
        }
        console.log(result);
        console.log("meteor call");
        testid = result;
        return (result);
    });
    console.log("outside call");
    console.log(testid);
    console.log(cusid);
    },
});

So i've been running some console.log tests and it seems it executes the meteor.call and keeps going down the line. Console.log of both testid and cusid return undefined but a couple seconds later I receive the console.log of result and the string "meteor call" from inside the meteor.call. Is there a way to wait for the meteor call to finish then run the rest of what is in my click function? so console output will go like:

  • "hello"
  • "outside call"
  • test id undefined
  • cusid undefined
  • "meteor call"
  • "result"
asiammyself
  • 219
  • 3
  • 12

2 Answers2

9

Keep in mind that the stripe API doesn't use Fibers. You need to put it in manually. The callback doesn't reach the client because by then it would have already got a response (its async)

You can use something like this to wait for a result from the stripe callback before a result is returned to the client:

var stripe = StripeAPI('mykeygoeshere');  // secret stripe API key
var Future = Npm.require('fibers/future');

var fut = new Future();

stripe.customers.create(
    { email: 'hello@example.org' },
    function(err, customer) {
        if (err) {
            console.log(err.message);
            fut.ret;
        }
        fut.ret("customer id", customer.id);
    }
);
return fut.wait();

Here a Future is used and it waits for a result to be received from the stripe callback before a result is returned to the client.

More info can be found on Fibers/Futures & Synchronous Callbacks incuding how to go about them & when to use them:

  1. Meteor: Calling an asynchronous function inside a Meteor.method and returning the result
  2. https://github.com/laverdet/node-fibers
  3. https://gist.github.com/possibilities/3443021
Community
  • 1
  • 1
Tarang
  • 75,157
  • 39
  • 215
  • 276
  • This worked great but when I went to make another Method that for example would delete the customer it throws an Error with ('Future resolved more than once'). So right now someone clicks submit gets all the info from the form and creates a stripe.customer then create a Meteor.user but say the Accounts.createUser throws an Error I run a method to delete the stripe customer. After I call my stripe del method it gives the error. – asiammyself Apr 22 '13 at 19:10
  • Could you post the updated code up? I need a bit more to go on, but I reckon that there are perhaps multiple returns being provided so you have to ensure fut.ret only runs once – Tarang Apr 23 '13 at 08:30
  • Updated code. Made Future a global var. Don't know if that would be the correct way to handle it but works for now. Function still doesn't seem to wait for return see edited post. – asiammyself Apr 24 '13 at 18:50
  • THank YOu!. I've been stuck on this issue for hours. I finally figured it out because of your answer. – Eric Leroy May 26 '13 at 15:55
1

Here's something simpler. Meteor now has Meteor.wrapAsync() for this kind of situation:

var stripe = StripeAPI("key");    
Meteor.methods({

    yourMethod: function(callArg) {

        var charge = Meteor.wrapAsync(stripe.charges.create, stripe.charges);
        charge({
            amount: amount,
            currency: "usd",
            //I passed the stripe token in callArg
            card: callArg.stripeToken,
        }, function(err, charge) {
            if (err && err.type === 'StripeCardError') {
              // The card has been declined
              throw new Meteor.Error("stripe-charge-error", err.message);
            }

            //Insert your 'on success' code here

        });
    }
});

I found this post really helpful: Meteor: Proper use of Meteor.wrapAsync on server

Community
  • 1
  • 1
jacksonkernion
  • 224
  • 2
  • 4
  • How do I find out on the client what's happening? I'm only getting undefined results after calling this server method. – quape Jan 24 '16 at 13:44