javascript meteor stripe-payments

javascript - Meteor: uso adecuado de Meteor.wrapAsync en el servidor



stripe-payments (4)

Como necesitará casi todas las funciones para envolver en Async, lo que debe hacer es usar este paquete https://atmospherejs.com/copleykj/stripe-sync que preenvuelve todas las funciones de banda con WrapAsync, lo que hace que su vida sea más fácil y limpia el código.

Antecedentes

Estoy tratando de integrar pagos en línea en mi sitio. Necesito crear un usuario de banda usando mi clave de banda privada. Estoy almacenando esta clave en mi servidor y llamo a un método de servidor para crear el usuario. Tal vez hay otra forma de lograr esto? Aquí está la api de la raya (copiada a continuación para mayor comodidad): https://stripe.com/docs/api/node#create_customer

//stripe api call var Stripe = StripeAPI(''my_secret_key''); Stripe.customers.create({ description: ''Customer for [email protected]'', card: "foobar" // obtained with Stripe.js }, function(err, customer) { // asynchronously called });

Mis intentos y resultados

He estado usando el mismo código de cliente con un código de servidor diferente. Todos los intentos dan inmediatamente undefined en el console.log del cliente (...) pero dan la respuesta adecuada en el servidor console.log (...):

//client Meteor.call(''stripeCreateUser'', options, function(err, result) { console.log(err, result); }); //server attempt 1 var Stripe = StripeAPI(''my_secret_key''); Meteor.methods({ stripeCreateUser: function(options) { return Meteor.wrapAsync(Stripe.customers.create({ description: ''Woot! A new customer!'', card: options.ccToken, plan: options.pricingPlan }, function (err, res) { console.log(res, err); return (res || err); })); } }); //server attempt 2 var Stripe = StripeAPI(''my_secret_key''); Meteor.methods({ stripeCreateUser: function(options) { return Meteor.wrapAsync(Stripe.customers.create({ description: ''Woot! A new customer!'', card: options.ccToken, plan: options.pricingPlan })); } });

También probé ambos sin Meteor.wrapAsync.

EDITAR: también estoy usando este paquete: https://atmospherejs.com/mrgalaxy/stripe


Desde Meteor.wrapAsync http://docs.meteor.com/#meteor_wrapasync puede ver que necesita pasarle una función y opcionalmente un contexto, mientras que en sus dos intentos está pasando el RESULTADO de llamar a la versión asíncrona de Stripe.customers.create .

Meteor.methods({ stripeCreateUser: function(options) { // get a sync version of our API async func var stripeCustomersCreateSync=Meteor.wrapAsync(Stripe.customers.create,Stripe.customers); // call the sync version of our API func with the parameters from the method call var result=stripeCustomersCreateSync({ description: ''Woot! A new customer!'', card: options.ccToken, plan: options.pricingPlan }); // do whatever you want with the result console.log(result); } });

Meteor.wrapAsync transforma una función asíncrona en una conveniente función de aspecto sincrónico que permite escribir código de aspecto secuencial. (Underhood todo todavía se ejecuta dentro del bucle de eventos asíncrono Node.js).

Necesitamos pasar a Meteor.wrapAsync nuestra función API ( Stripe.customers.create ) junto con el contexto de la función, es decir, this dentro del cuerpo de la función API, que en este caso es Stripe.customers .

EDITAR:

¿Cómo recuperar errores?

Las funciones de API de estilo de nodo tradicional generalmente toman una devolución de llamada como último argumento que se llamará en última instancia cuando se complete la tarea requerida. Esta devolución de llamada toma 2 argumentos: error y datos, cualquiera de los dos será nulo según el resultado de la llamada.

¿Cómo accedemos al objeto de error utilizando las funciones sincrónicas Meteor.wrapAsync devueltas por Meteor.wrapAsync ?

Tenemos que confiar en el uso de bloques try / catch, porque en caso de error, será arrojado por la función de sincronización en lugar de pasarlo como primer argumento de la devolución de llamada de la función asíncrona.

try{ var result=syncFunction(params); console.log("result :",result); } catch(error){ console.log("error",error); } // is the equivalent of : asyncFunc(params,function(error,result){ if(error){ console.log("error",error); return; } console.log("result :",result); });

¿Por qué no se necesita pasar Stripe?

JavaScript no tiene un concepto de "espacio de nombres", por lo que los desarrolladores de API utilizan el truco común de definir un objeto global que actúa como espacio de nombres de API, las propiedades definidas en este objeto son "submódulos" de la API. Significa que Stripe.customers es un submódulo de la API Stripe que expone funciones relacionadas con los clientes, y como tales funciones, this contexto es Stripe.customers , no Stripe .

Puede probarlo usted mismo copiando y pegando este código de burla en la consola de su navegador:

Stripe={ customers:{ create:function(){ console.log(this==Stripe.customers); } } };

Y luego llamando a la función de código auxiliar en la consola de su navegador de esta manera:

> Stripe.customers.create(); true


En primer lugar, gracias a @saimeunt por su respuesta, que deja claros algunos conceptos difíciles. Sin embargo, tuve el problema de querer una devolución de llamada asíncrona clásica (err, result) que mostrara tanto el error como el resultado en el cliente, para poder dar mensajes informativos en el navegador.

Lo resolví de esta manera:

Código del servidor:

var Stripe = StripeAPI(STRIPE_SECRET_KEY); Meteor.methods({ createCust: Meteor.wrapAsync(Stripe.charges.create, Stripe.charges) });

Codigo del cliente:

var stripeCallOptions = { description: ''Woot! A new customer!'', card: ccToken, plan: pricingPlan }; Meteor.call(''createCust'', stripeCallOptions, function(error, result){ console.log(''client error'', error); console.log(''client result'', result); });

Se ve bien. Sin embargo, lamentablemente, wrapAsync tiene un error abierto, (consulte https://github.com/meteor/meteor/issues/2774 ) porque no restablece el error adecuado para la persona que llama. Un genio llamado Faceyspacey ha escrito un reemplazo llamado Meteor.makeAsync () que encontrará en la página de error que mencioné, que sin embargo devuelve el resultado O el error a la variable ''resultado'', dejando la variable ''error'' indefinida. Eso está bien para mí por ahora, al menos tengo un gancho en el objeto de error adecuado.

Si usa makeAsync () necesitará importar futuros como este:

Meteor.startup(function () { //this is so that our makeAsync function works Future = Npm.require(''fibers/future''); });


Otra opción es este package que logra los objetivos similares.

meteor add meteorhacks:async

Del paquete README:

Async.wrap (función)

Envuelva una función asincrónica y permita que se ejecute dentro de Meteor sin devoluciones de llamada.

//declare a simple async function function delayedMessge(delay, message, callback) { setTimeout(function() { callback(null, message); }, delay); } //wrapping var wrappedDelayedMessage = Async.wrap(delayedMessge); //usage Meteor.methods({ ''delayedEcho'': function(message) { var response = wrappedDelayedMessage(500, message); return response; } });