Methods, Promises and Errors?


#1

I’m having some trouble getting an error from the server to the client:

client:

promisepay.captureDeviceId(function(deviceId){
      data.deviceId = deviceId;
     Meteor.call('createPaymentAccount', data, function(error, response){
        if (error) { 
          Bert.alert(error.reason, 'danger'); 
          return; 
        }
        console.log(response);
     });
});

server:

Meteor.methods({
	createPaymentAccount: function(data){
		check(data, Object);

		const docToInsert = data;

                //http call to POST using node-promisepay
		ppClient.users.create(docToInsert)
               .then(function(response){
			console.log('response: ' + response);			 
		}, function(error){
			throw new Meteor.Error("account-error", "Something went wrong creating your account.");
		});

	}
});

It seems this is throwing the error on the server. I’m also getting the response on the client before the method is done running.

Do I need a Meteor.bindEvent or some asyncWait stuff?


#2

forget to add the return keyword to make it synchronous I guess. So:

Meteor.methods({
	createPaymentAccount: function(data){
		check(data, Object);

		const docToInsert = data;

                //http call to POST using node-promisepay
		return ppClient.users.create(docToInsert)
               .then(function(response){
			console.log('response: ' + response);			 
		}, function(error){
			throw new Meteor.Error("account-error", "Something went wrong creating your account.");
		});

	}
});

#3

On the server side, I wouldn’t use async functions. Instead, use Meteor.wrapAsync to make it synchronous. Be sure to add this.unblock() as the first line in your method so the client can make other method calls, e.g.:

Meteor.methods({
	createPaymentAccount: function(data){
		check(data, Object);

                this.unblock();
		const docToInsert = data;

#4

Hang on, I do it a completely different way? Image a collection called docTemplate with only 1 field, its name…

Then (1) insert method with nothing exciting…

export const insertDocTemplate = new ValidatedMethod({
  name: 'docTemplate.insert',
  validate: new SimpleSchema({
    docTemplateName: { type: String },
  }).validator(),
  run({ docTemplateName }) {
    if (Meteor.isServer) {
      return DocTemplates.insert({ docTemplateName });
    }
  },
});

(2) insert helper and promise

import { Meteor } from 'meteor/meteor';
import { check } from 'meteor/check';

// DocTemplate Method
import { insertDocTemplate } from './methods.js';

// THE CLEAN INSERT HERE>>>
export function addDocTemplate(newDocTemplateName) {
  check(newDocTemplateName, String);

  const newDocTemplate = {
    docTemplateName: newDocTemplateName,
  };

  return new Promise((resolve, reject) => {
    insertDocTemplate.call(newDocTemplate, (err, result) => {
      if (err) {
        reject (err);
      } else {
        resolve (result);
      }
    });
  });
}

// PROMISIFIED VERSION HERE>>>
export async function addDocTemplatePromise(entityId, newDocTemplateName) {
  await addDocTemplate(newDocTemplateName)
    .then(
      function(response) {
        return response;
      },
      function(error) {
        throw new Meteor.Error(error);
      }
    );
}

This lets me see the error on the client. Unfortunately it seems hard to test… Tests:

describe('DocTemplate: insertHelpers', function() {
  beforeEach(function () {
    if (Meteor.isServer) {
      resetDatabase();
    }
  });

  if (Meteor.isServer) {

    it('addDocTemplate', function() {
      const dodgyEntityId = 'dodgyEntityId';
      const testDocTemplateName = 'Test Doc Template';

      const newDocTemplateId = addDocTemplate(dodgyEntityId, testDocTemplateName);
      assert.typeOf(newDocTemplateId, 'object');
      console.log(newDocTemplateId);
    });

    it('addDocTemplatePromise', function() {
      const dodgyEntityId = 'dodgyEntityId';
      const testDocTemplateName = 'Test Doc Template';

      const newDocTemplateId = addDocTemplatePromise(dodgyEntityId, testDocTemplateName);
      console.log(newDocTemplateId);
    });
  }
});

Looks like ass on the tests: @ffxsam/@a.com, does this look legit to you? For whatever reason the actual promisified function does not return the promise?

I20161006-11:47:07.538(11)? MochaRunner.runServerTests: Starting server side tests with run id 3xMmzaiSoqSQpExfG
I20161006-11:47:07.590(11)? Promise { 'mhdyqSJW8Eqd5naLt' }
I20161006-11:47:07.606(11)? Promise {
I20161006-11:47:07.607(11)?   _c: [],
I20161006-11:47:07.607(11)?   _a: undefined,
I20161006-11:47:07.607(11)?   _s: 0,
I20161006-11:47:07.607(11)?   _d: false,
I20161006-11:47:07.608(11)?   _v: undefined,
I20161006-11:47:07.608(11)?   _h: 0,
I20161006-11:47:07.608(11)?   _n: false }

EDIT: Am i doing this completely wrong?


#5

I’m not clear on why you need to Promisifiy your document insertion.


#6

this was just a made up example so working with something very simple for illustrative purposes… would chain more promises after the .then in a real case. The query is how to test promise nicely…

tat