Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

meteor server side method throwing not catched by callback in client #559

Closed
frankapimenta opened this issue Dec 2, 2016 · 19 comments
Closed

Comments

@frankapimenta
Copy link

frankapimenta commented Dec 2, 2016

I've defined a server side meteor method in a class.
I throw a meteor error but the callback in the client side is not catching it.

// code makes no sense just as an example.
// server side

Post.extend({
  addModerator(id) {
    // this error is undefined in the callback parameter.
    throw new Meteor.Error('blabla', 'because blabla');
});

// client side

Post.callMethod('addModerator', id, (err, result) => { console.log(err, result) });

// log result in browser console -> undefined, undefined.
@lukejagodzinski
Copy link
Member

It should be:

Post.extend({
  meteorMethods: {
    addModerator(id) {
      // this error is undefined in the callback parameter.
      throw new Meteor.Error('blabla', 'because blabla');
    }
  }
});

@frankapimenta
Copy link
Author

Yes. :D thought of everything but that. I'm sorry about it.
however the browser shows an uncaught exception and the callback is not executed.

@lukejagodzinski
Copy link
Member

I've just checked and I'm 100% sure that it works, so you're probably doing something wrong. Create reproduction repository.

@pgiani
Copy link

pgiani commented Dec 14, 2016

Same problem here I resolve by a warping the call on try catch

try { Post.callMethod('addModerator', id, (err, result) => { console.log(err, result) }); } catch (e) { console.log(e); }

Not ideal but it works

@davidsavoie1
Copy link

I do have the same type of problem...

On the client:

const person = new Person();
person.createFromAdmin((err, res) => {
  console.log({ err, res });
});

On the server:

export const Person = Class.create({
  name: 'Person',
  collection: Persons,
  fields: {
    /* Fields */
  },
  meteorMethods: {
    createFromAdmin() {
      throw new Meteor.Error('blabla', 'because blabla');
    },
  },
});

I do get the callback response Object {err: errorClass, res: undefined} in the console, but only after I also get the actual error Exception while simulating the effect of invoking '/Astronomy/execute'..., as if I didn't catch it.

Whatever the try... catch implementations I use either on client or server, I get the same result. Using person.callMethod() yields the same also. I can't get a more straightforward example here...

Am I missing something obvious? Thanks!

@lukejagodzinski
Copy link
Member

@davidsavoie1 create reproduction repository

@davidsavoie1
Copy link

davidsavoie1 commented Feb 15, 2018

@lukejagodzinski Here it is!. It's the first time a create a repo on Github for debugging, so tell me if there's anything missing!

In my previous post, I wrote that the class definition is on the server, but that's incorrect... It's actually defined in the imports/api/Person/Person.js file, which is imported in the UI files.

In the repo, everything is directly in the client/main.js file.

@lukejagodzinski
Copy link
Member

lukejagodzinski commented Feb 15, 2018

@davidsavoie1 the repository is ok.
Your problem is in using new Mongo.Collection('tests') instead of new Mongo.Collection(null) for local collection. When you change that line of code, everything will start working. It's very common when using client only collection in Meteor to forget that it requires null as the first argument.

However, I see that there is a problem with lack of the /Astronomy/execute method when no serverside collection is defined. I will fix that but it's not related to your problem.

@lukejagodzinski
Copy link
Member

@davidsavoie1 I'm trying to fix an issue that I've encountered when working with your reproduction repository and I've noticed that apparently there is some issue in Meteor. As when testing such a code in the browser console:

Meteor.methods({test() { throw new Meteor.Error("error"); }});
Meteor.call("test", (err) => { console.log(err); });

I get the following output:

Exception while simulating the effect of invoking 'test' errorClass {isClientSafe: true, error: "error", reason: undefined, details: undefined, message: "[error]", …} Error: [error]
    at MethodInvocation.test (<anonymous>:1:32)
    at http://localhost:3000/packages/ddp-client.js?hash=69c1d15adcf9b913cb4704b652adeff4bc462aa8:1033:27
    at Meteor.EnvironmentVariable.EVp.withValue (http://localhost:3000/packages/meteor.js?hash=b0f12795c8cc1423b5850502871996903f947ed5:1140:15)
    at Connection.apply (http://localhost:3000/packages/ddp-client.js?hash=69c1d15adcf9b913cb4704b652adeff4bc462aa8:1024:62)
    at Connection.call (http://localhost:3000/packages/ddp-client.js?hash=69c1d15adcf9b913cb4704b652adeff4bc462aa8:906:19)
    at <anonymous>:2:8
errorClass {isClientSafe: true, error: 404, reason: "Method 'test' not found", details: undefined, message: "Method 'test' not found [404]", …}

It says that there is not test method but simulation works properly. Apparently, it's not possible to create client only Meteor method (that would not throw an error) and if you're using client only collection then it won't create those methods on the server.

Another test shows the same result:

Meteor.methods({test() { return "test" }});
Meteor.call("test", (err, result) => { console.log(err, result); });

Output:

errorClass {isClientSafe: true, error: 404, reason: "Method 'test' not found", details: undefined, message: "Method 'test' not found [404]", …} undefined

So what's the solution? Do not use meteorMethods for client only collections. You can probably use them safely on the server only collections. Instead you should use helpers.

@davidsavoie1
Copy link

@lukejagodzinski OK, I get what you mean... I've adopted wrong pattterns because the last project I've done with Astronomy was a client only one. That's why I've declared everything in the client only.

I've modified the code in the repo to ensure that the collection is defined both on the server and the client by importing the class in both server/main.js and client/main.js. I still get the same issue.

I'm really sorry if there's some fundamental concept I don't grasp here that has nothing to do with Astronomy, but your help is very much appreciated...

@lukejagodzinski
Copy link
Member

@davidsavoie1 update Astronomy version to 2.5.5 and error should be gone. I was using a wrong utility function to execute Meteor method which didn't throw stub exception and instead it was logging it to the console as it's done by default in Meteor but it's not good for Astronomy.

@lukejagodzinski
Copy link
Member

@davidsavoie1 btw. thanks for the reproduction! It helped fix one more issue :)

@davidsavoie1
Copy link

Ah great! I'm really glad to know that I do understand what I'm doing after all! 😆 Thanks to you!

@davidsavoie1
Copy link

@lukejagodzinski I just tried the repo code again with version 2.5.5 of Astronomy and I think there's still an issue (or again, maybe it's my understanding). I don't seem to catch and handle a thrown error even when using a callback. The error is considered Uncaught. The problem exists only if the method throws an error directly (but I guess it simulates a real unpredictable error, right?). Here's a simple example:

Class definition

const Test = Class.create({
  name: 'Test',
  collection: new Mongo.Collection('tests'),
  fields: {
    /* Fields */
  },
  events: {
    beforeSave(e) {
      throw new Meteor.Error('save-error', 'Could not save!');
    },
  },
  helpers: {
    helper() {
      throw new Meteor.Error('helper-error', 'because blabla');
    },
  },
  meteorMethods: {
    failMethod() {
      throw new Meteor.Error('failMethod-error', 'because blabla');
    },
    successMethod() {
      return true;
    },
  },
});

Tests on the client

const test1 = new Test();

/* No error */
test1.successMethod((err, res) => {
  console.log('From sucessMethod', { err, res });
});

/* Caught */
test1.save((err, res) => {
  console.log('From save', { err, res });
});

/* Uncaught */
test1.failMethod((err, res) => {
  console.log('From failMethod', { err, res });
});

/* Uncaught */
test1.helper((err, res) => {
  console.log('From helper', { err, res });
});

The save callback catches the error properly, but not the others.
I updated the repo again, so you can test it.

@davidsavoie1
Copy link

I added another test to see if I get the same kind of problem with regular Meteor Methods and I don't.

Meteor.methods({
  myMeteorMethod() {
    throw new Meteor.Error('myMeteorMethod-error', 'Blablabla');
  },
});

/* Caught */
Meteor.call('myMeteorMethod', (err, res) => {
  console.log('From myMeteorMethod', { err, res });
});

The error gets caught even with a directly thrown error. That's the behavior I'm expecting.
Updated repo. Thanks again!

@lukejagodzinski
Copy link
Member

Helpers do not take a callback function as the last argument. After my fix in 2.5.5 you can use Meteor methods safely on the client only collections, so what I said previously is no longer true. You don't have to use helpers. Helpers are actually designed for things similar to helpers in Blaze templates.

And yes there is still a bug I haven't noticed yesterday. I will fix it later today. It will be fixed in 2.5.6.

@lukejagodzinski
Copy link
Member

@davidsavoie1 fixed in 2.5.6

@davidsavoie1
Copy link

@lukejagodzinski You're the best! 😉 Thanks for the quick responses, I'll be enjoying Astronomy for a while in the coming weeks! And you're absolutely right about helpers not using error callbacks, I had overlooked this detail. And it's great that Meteor Methods can now be used with local collections. It'll be much clearer that way!

Dziękuję bardzo

@lukejagodzinski
Copy link
Member

@davidsavoie1 you're welcome :)

Hehe :)
Proszę bardzo

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

4 participants