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.