SamuelMS
SamuelMS

Reputation: 1146

Meteor method returns undefined to the client (asynchronous)

I've been working on integrating Google Recaptcha into a Meteor and AngularJS web application. Everything was smooth sailing until I had to validate the recaptcha response -- for some bizarre reason, I can't get an async response from the backend to the frontend.

I've tried a lot of different variations and have read many, many posts on SO and the internet in general, but with no luck -- so I opted to post my own question.


Here's what I'm doing:

Client:

Meteor.call('recaptcha.methods.validateRecaptcha', { 'response' : this.recaptcha.getResponse(this.id) }, function(error, result) {
    // error and result are both undefined
    console.log('Do something with the ' + error + ' or ' + result + '.');
}

So, I'm calling a Meteor method and passing in a callback that is run when the method is done. However, the error and result parameters are both undefined.

Server:

run: function(data) {
    if (this.isSimulation) {
        /*
         * Client-side simulations won't have access to any of the
         * Meteor.settings.private variables, so we should just stop here.
         */
        return;
    }

    return Meteor.wrapAsync(HTTP.post)(_someUrl, _someOptions);
}

That last line is a shortened version of the sync/async structure that I've found in several Meteor guides (I also tried this version), namely:

var syncFunc = Meteor.wrapAsync(HTTP.post);
var result = syncFunc(Meteor.settings.private.grecaptcha.verifyUrl, _options);
return result;

I've also tried a version using Futures:

var Future = Npm.require( 'fibers/future' );
var future = new Future();
var callback = future.resolver();
HTTP.post(Meteor.settings.private.grecaptcha.verifyUrl, _options, callback);

return future.wait();

Now, the intention here is that I use Meteor.call() to call this method from the client, the client-side stub runs (to prevent simulation errors since we use private Meteor.settings variables in the real non-SO server-side code) and returns immediately (which happens), and the server hits Google's Recaptcha API (which happens and the server receives a response) before returning the result to the client (which doesn't happen -- the callback occurs but with no error/success data).

My thought is that one of two things are happening:

  1. I'm just doing something wrong and I'm not properly sending the data back to the client.
  2. The synchronous client stub (which returns immediately) is telling the client that the server response isn't important, so it never waits for the proper asynchronous response.

Could any of the Meteor gurus weigh in here and let me know what's going on and how to get async requests to play nicely in a Meteor application?

Thanks!

Upvotes: 1

Views: 572

Answers (1)

Kishor
Kishor

Reputation: 2677

From the documentation for HTTP.call, which is the generic version of HTTP.post, it says

Optional callback. If passed, the method runs asynchronously, instead of synchronously, and calls asyncCallback. On the client, this callback is required.

So, on server, you can run it asynchronously like this

run: function(data) {
    if (this.isSimulation) {
        /*
         * Client-side simulations won't have access to any of the
         * Meteor.settings.private variables, so we should just stop here.
         */
        return;
    }

    // No need to pass callback on server.
    // Since this part is not executed on client, you can do this
    // Or you can use Meteor.isClient to run it asynchronously when the call is from client.
    return HTTP.post(Meteor.settings.private.grecaptcha.verifyUrl, _options);
}

Upvotes: 2

Related Questions