PageRenderTime 43ms CodeModel.GetById 21ms RepoModel.GetById 0ms app.codeStats 0ms

/posts/backend/advanced/nodejs-error-handling.md

https://github.com/jrgcubano/jsrecipes
Markdown | 121 lines | 95 code | 26 blank | 0 comment | 0 complexity | 87cad8f82ec44fe776ac1297603d7867 MD5 | raw file
  1. <img src="http://nodeblog.files.wordpress.com/2011/07/nodejs.png" height=92">
  2. Error handling is a highly debatable topic in Node.js community because there
  3. is no single true way to do it. Working with Node.js for over 2 years I can
  4. say that error handling is one of the most annoying problems to deal with when
  5. building Node.js web apps. If you are not careful, a single unhandled error
  6. can bring down your entire application, leaving it in the crashed state.
  7. What's even worse, sometimes it's not easy to find the source of unhandled
  8. exceptions due to cryptic and unhelpful stack traces. In other words, you
  9. could ocassionaly see your app crash, but have no idea what causes it. It could
  10. be a bug in your code or a certain bug that only occurs on a specific
  11. Node.js version on a particular operating system.
  12. There are primarily three schools of thoughts on error handling:
  13. - Let the application crash and restart it.
  14. - Handle all possible errors and never crash.
  15. - Balanced approach between the two.
  16. #### <span class="text-danger">Approach 1:</span> Handle errors in routes.
  17. You are probably aware that most Node.js modules, as a general rule, have an
  18. error object as the first argument in a callback. Unless you properly
  19. handle that error, your app will likely crash sooner or later.
  20. Look at this code below. It simply means if an error is raised for whatever
  21. reason, the `if (err)` line will intercept it and do something with it, in this case
  22. `throw` it. In other words your application will still crash.
  23. ```javascript
  24. app.get('/', function(req, res) {
  25. Item.find(function(err, items) {
  26. if (err) throw err;
  27. console.log(items);
  28. });
  29. });
  30. ```
  31. The difficult part of handling errors is you have to decide what
  32. do you want to do when an error occurs? What do you think should happen if we
  33. can't retrieve our items from database? There is no correct answer, it will
  34. ultimately depend on your application. Personally, I don't believe that we
  35. should crash and restart the server for errors like these.
  36. A better approach would be to display a flash notifications with
  37. "Items could not be retrieved from database. Please try again" or if you
  38. don't want to do flash notificans you could simply display a blank page with
  39. that same text:
  40. ```javascript
  41. app.get('/', function(req, res) {
  42. Item.find(function(err, items) {
  43. if (err) {
  44. return res.send('Items could not be retrieved from database. Please try again.');
  45. }
  46. console.log(items);
  47. });
  48. });
  49. ```
  50. ![](images/backend/advanced/nodejs-error-handling-1.png)
  51. To me that's a better approach than crashing the server and letting it restart
  52. itself via [supervisor](https://github.com/isaacs/node-supervisor) or
  53. [forever](https://github.com/nodejitsu/forever) modules. The reason why I
  54. called this "in-place" error handling is because you are taking care of errors
  55. inside `if (err)` block for each asynchronous operation that returns an error object
  56. as the first argument. In [Hackathon Starter](https://github.com/sahat/hackathon-starter)
  57. `api.js` controller alone, there are over 79 occurences of error objects.
  58. Handling each `err` individually would result in tremendous amount of code
  59. duplication.
  60. The next best thing you can do is to delegate all error handling logic to an
  61. Express middleware.
  62. #### <span class="text-danger">Approach 2:</span> Handle errors in middleware.
  63. ```javascript
  64. app.get('/', function(req, res, next) {
  65. Item.find(function(err, items) {
  66. if (err) return next(err);
  67. console.log(items);
  68. });
  69. });
  70. ```
  71. **Note:** It is important to **return** inside `if (err) { ... }` otherwise your
  72. code will just continue executing and eventually crash.
  73. Two things to note here:
  74. 1. An extra route parameter `next`.
  75. 2. When error occurs, call `return next()` and pass it an error object.
  76. Then add this middleware after all other Express middlewares:
  77. ```javascript
  78. app.use(function(err, req, res, next) {
  79. console.error(err.stack);
  80. return res.send(500, { message: err.message });
  81. });
  82. ```
  83. This middleware will print out error stack to console and render a JSON page
  84. with the error message. This is just an example code. If you are using some
  85. third-party logging tools, this is where you could trigger error events. It's
  86. totally up to you in deciding what to do with those errors. Or perhaps this
  87. is where you would display a generic custom error page with the error message.
  88. #### Bonus: Error Handling in Node.js by Jamund Ferguson
  89. <iframe width="560" height="315" src="//www.youtube.com/embed/p-2fzgfk9AA" frameborder="0" allowfullscreen></iframe>
  90. <hr>
  91. #### <i class="fa fa-lightbulb-o text-danger"></i> Additional Resources
  92. 1. [Node.js Error Handling Patterns](http://www.nodewiz.biz/nodejs-error-handling-pattern)
  93. 2. [Best Practices for Error Handling in Node.js](http://www.joyent.com/blog/best-practices-for-error-handling-in-node-js)
  94. 3. [Error handling in node.js](http://machadogj.com/2013/4/error-handling-in-nodejs.html)
  95. 4. [Node.js Best Practice Exception Handling](https://gist.github.com/balupton/5560110)