Node.js Error Handling -- how to deal with undefined values causing errors

Take this URL for instance: https://api.eveonline.com/eve/CharacterID.xml.aspx?names=Khan

Using xml2js node.js module you may parse that XML, although it does not look pretty:

var CharacterID = response.eveapi.result[0].rowset[0].row[0].$.characterID;

The app crashed after 2 weeks of running, all because rowset[0] was undefined. Prior to that it crashed because eveapi was not defined. Seriously, does my if-else has to be like this just to prevent server from crashing due to stupid undefined object errors?

 if (!response.eveapi || 
     !response.eveapi.result[0] || 
     !response.eveapi.result[0].rowset[0] || 
     !response.eveapi.result[0].rowset[0].row[0]) {
            return res.send(500, "Error");

Besides the obvious if (err) return res.send(500, "Error"); error handling where applicable, what is the general practice for undefined errors?

I wrote a library for this kind of thing, called dotty (https://github.com/deoxxa/dotty).

In your case, you could do this:

var dotty = require("dotty");

var CharacterID = dotty.get(response, "eveapi.result.0.rowset.0.row.0.$.characterID");

In the case of the path not being resolvable, it'll just return undefined.

As you've discovered, undefined is not itself an error, but using undefined as an array/object is an error.

x = {'a': { 'b': { 'c': { 'd': [1,2,3,4,5]} } } } ;
try { j = x.a.b.c.e[3] } catch(e) { console.log(e); }

prints

[TypeError: Cannot read property '3' of undefined]

This suggests to me that try/catch can be used with your code to return an error code, and if desired, an error text (or just stick the error text in console.log, a database or local file).

In your case, that could look like:

var CharacterID; // can't define it yet

try {
  CharacterID = response.eveapi.result[0].rowset[0].row[0].$.characterID;
} catch(e) {
// send description on the line with error
  return res.send(500, "Error: NodeJS assigning CharacterID: "+e); 
// return res.send(500, "error");  use this one if you dont want to reveal reason for errors
}

// code here can assume CharacterID evaluated.  It might still be undefined, though.

Maybe this function helps?

function tryPath(obj, path) {
    path = path.split(/[.,]/);
    while (path.length && obj) {
        obj = obj[path.shift()];
    }
    return obj || null;
}

For your code you'd use:

if (tryPath(response,'eveapi.result.0.rows.0.row.0') === null) {
  return res.send(500, "Error");
}

jsFiddle example
jsFiddle same example, but as extension to Object.prototype