Handling errors using Meteor methods and HTTP

2,892 views
Skip to first unread message

Jon James

unread,
May 1, 2014, 6:52:56 PM5/1/14
to meteo...@googlegroups.com
Running one of Meteor's HTTP methods in a Meteor method synchronously returns a 500 Internal Server Error to the client regardless of the HTTP status code returned. If I use try/catch, it returns a string that I would have to parse on the client in order to extract the data I want (status code).

I'm working with a remote RESTful API that returns a few different HTTP status codes, and I need to get the exact status code on the client if there's an error, in order to prompt the user to various actions.

It seems like the best available way to do what I want is to use _wrapAsync like below and then use duck typing in the Meteor method to check if it's an error.

var postCatchError = Meteor._wrapAsync(function(url, options, resolve) {
  HTTP.post(url, options, function(err, res) {
    if (err) {
      resolve(null, err.response);
    } else {
      resolve(null, res);
    }
  });
});

Meteor.methods({
  someMethod: function(x) {
    var response;
    response = postCatchError("http://something.com/api/whatevs", {
      data: {
        someArg: x,
        someBool: true
      },
      headers: {
        'Content-type': 'application/json'
      }
    });
    if (response && response.statusCode) {
      throw new Meteor.Error(response.statusCode, "some message");
    } else {
      return response;
    }
  }
});

Seems like a lot of work just to get the correct status code on the client!

I'm interested to know if anyone else has dealt with this in a different/better way.

Thanks!

Jon James

unread,
May 1, 2014, 7:11:36 PM5/1/14
to meteo...@googlegroups.com
Oh forgot to mention this is all happening on the server.

Austin Rivas

unread,
May 1, 2014, 8:27:43 PM5/1/14
to meteo...@googlegroups.com
Take a look at arunodas npm package, specifically at his async helpers. They are a lifesaver.

Avital Oliver

unread,
May 1, 2014, 11:03:26 PM5/1/14
to meteo...@googlegroups.com
Although it's hard to tell (though technically documented), the exception thrown by HTTP.call does have information like response code. Unfortunately console.log doesn't print that (I actually don't know why. If anyone has ideas on how to improve it *please* let me know).

If you log the `response` field of the error object you'll see more:

I20140501-20:00:50.063(-7)? { statusCode: 404,
I20140501-20:00:50.063(-7)?   content: '<!DOCTYPE html>\n<html lang=en>\n  <meta charset=utf-8>\n  <meta name=viewport content="initial-scale=1, minimum-scale=1, width=device-width">\n  <title>Error 404 (Not Found)!!1</title>\n  <style>\n    *{margin:0;padding:0}html,code{font:15px/22px arial,sans-serif}html{background:#fff;color:#222;padding:15px}body{margin:7% auto 0;max-width:390px;min-height:180px;padding:30px 0 15px}* > body{background:url(//www.google.com/images/errors/robot.png) 100% 5px no-repeat;padding-right:205px}p{margin:11px 0 22px;overflow:hidden}ins{color:#777;text-decoration:none}a img{border:0}@media screen and (max-width:772px){body{background:none;margin-top:0;max-width:none;padding-right:0}}#logo{background:url(//www.google.com/images/errors/logo_sm_2.png) no-repeat}@media only screen and (min-resolution:192dpi){#logo{background:url(//www.google.com/images/errors/logo_sm_2_hr.png) no-repeat 0% 0%/100% 100%;-moz-border-image:url(//www.google.com/images/errors/logo_sm_2_hr.png) 0}}@media only screen and (-webkit-min-device-pixel-ratio:2){#logo{background:url(//www.google.com/images/errors/logo_sm_2_hr.png) no-repeat;-webkit-background-size:100% 100%}}#logo{display:inline-block;height:55px;width:150px}\n  </style>\n  <a href=//www.google.com/><span id=logo aria-label=Google></span></a>\n  <p><b>404.</b> <ins>That’s an error.</ins>\n  <p>The requested URL <code>/SDGJKLDJGKDL</code> was not found on this server.  <ins>That’s all we know.</ins>\n',
I20140501-20:00:50.063(-7)?   headers:
I20140501-20:00:50.064(-7)?    { 'content-type': 'text/html; charset=UTF-8',
I20140501-20:00:50.064(-7)?      'x-content-type-options': 'nosniff',
I20140501-20:00:50.064(-7)?      date: 'Fri, 02 May 2014 03:00:48 GMT',
I20140501-20:00:50.064(-7)?      server: 'sffe',
I20140501-20:00:50.064(-7)?      'content-length': '1437',
I20140501-20:00:50.064(-7)?      'x-xss-protection': '1; mode=block',
I20140501-20:00:50.065(-7)?      'alternate-protocol': '80:quic' },
I20140501-20:00:50.065(-7)?   data: null }


--
You received this message because you are subscribed to the Google Groups "meteor-talk" group.
To unsubscribe from this group and stop receiving emails from it, send an email to meteor-talk...@googlegroups.com.
For more options, visit https://groups.google.com/d/optout.



--
PS. I genuinely *really* like receiving feedback of any kind. Leave it anonymously at http://www.admonymous.com/avital

Jon James

unread,
May 2, 2014, 2:33:56 AM5/2/14
to meteo...@googlegroups.com
Hi Avital,

Thank you for your response. I did go through the docs in detail today before/while trying what I did, and as you can see in postCatchError (in my first code example), I'm specifically pulling out the response field of the error. This works when I use HTTP.post with a callback (async). However, using HTTP.post without a callback (sync) directly inside a Meteor method returns only a 500 internal server error to the client, regardless of which status code the HTTP response actually returns. This error does not have a response field (I just double-checked). 

The more I think about it, the more this makes sense. But it would still be nice to be able to get the original error in the Meteor.call callback somehow.

This works and is simpler than my first example:

Meteor.methods({
  someMethod: function(x) {
    var response;
    try {
      response = HTTP.post("http://something.com/api/whatevs", {
        data: {
          someArg: x,
          someBool: true
        },
        headers: {
          'Content-type': 'application/json'
        }
      });
    } catch (e) {
      response = e.response;
    } finally {
      return response;
    }
  }
});

Simply returning the caught "e" wasn't of much use.

Anyway, I hope my examples help other people who might have struggled with the issue.


That's me at the bottom of the article :) thanks for your suggestion.

Jon

Arunoda Susiripala

unread,
May 2, 2014, 3:03:07 AM5/2/14
to meteo...@googlegroups.com
Hi Jon,

What you are doing is correct and the best way to do it. 
Normally, we should not send errors (codes and messages) happens on the server to the client. 

But your case is different, you need to proxy response code. This seems like a good solution which you can create a package. 
--
You received this message because you are subscribed to the Google Groups "meteor-talk" group.
To unsubscribe from this group and stop receiving emails from it, send an email to meteor-talk...@googlegroups.com.
For more options, visit https://groups.google.com/d/optout.


--

Reply all
Reply to author
Forward
0 new messages