There's a lot of blog posts around the internet talking about the mechanics 
of handling errors, be it domains or process.on("uncaughtException"). I 
can't find much definitive talk about the philosophy of error handling 
though. Specifically when should a function return an error cb(err), or 
return an error state such as cb(null, { success : false, message : "Some 
useful message", resp : httpResponse }).

In example, lets imagine we're creating a social media NPM package which 
has an async function which queries a social media API via an HTTP call 
using the popular request module and returns some posts. Our function takes 
3 arguments a userid and a count and a callback. There are a variety of 
exit scenarios for this function:

1. Malformed arguments sent to the function such as a missing cb or a 
null/undefined/incorrectly formatted userid.
2. Unable to reach the service via HTTP.
3. Service returned a non-200 status code for some reason, maybe we're 
being rate-limited.
4. Reached the service, but the call failed at the service due to invalid 
parameters, some services return a 200 status code for this type of failure 
other's return a non-200 status code.
5. Reached the service, the call succeeded but returned an empty array of 
posts.
6. Reached the service, the call succeeded and returned data.
7. The function throws an unhandled error due to programmer mistake.

Usually my philosophy for handling errors in this case would be:

1. cb(new Error("Invalid parameters, must pass a callback"));
2. cb(err); // the error that was returned by the http request
3. cb(null, { success : false, message : "Service returned a " + 
resp.statusCode + " status code", resp : resp });
4. cb(null, { success : false, message : serviceResponse.message, resp : 
resp });
5. cb(null, { success : true, data : [] });
6. cb(null, { success : true, data : posts });
7. Whoops, let error bubble up to the application employing our package and 
it will handle it or crash.

That's just one way to approach the problem. It could be argued that cases 
1 - 4 should all cb an error and that the error object should be packed 
with the additional data to help debug or be a custom error type. Yet at 
the same time some people argue it's a bad idea to pack additional 
non-standard keys on to Error objects because it results in inconsistency 
between Error objects and modules. If every npm module packed it's Error 
objects with custom keys wouldn't we end up in a pretty chaotic situation? 
In addition, if that error is thrown or console.error() those extra keys 
will not show up because of the native behavior of 
Error.prototype.toString(). 

Yet another approach would be for 1 - 4 to return an error AND the 
additional data. Such as cb(new Error(serviceResp.message), { success : 
false, message : serviceResp.message, resp : resp }). This way downstream 
modules have the useful debugging information available, but we still end 
up treading down the error pathway of control flow structures such as async 
and promises. In example, in async if an error is returned it 
short-circuits all the way to the end.

Any guidance on this subject?

-- 
Job board: http://jobs.nodejs.org/
New group rules: 
https://gist.github.com/othiym23/9886289#file-moderation-policy-md
Old group rules: 
https://github.com/joyent/node/wiki/Mailing-List-Posting-Guidelines
--- 
You received this message because you are subscribed to the Google Groups 
"nodejs" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to [email protected].
To post to this group, send email to [email protected].
To view this discussion on the web visit 
https://groups.google.com/d/msgid/nodejs/c49f823e-bf6b-455c-8bac-db70f4710bc6%40googlegroups.com.
For more options, visit https://groups.google.com/d/optout.

Reply via email to