{"id":545,"date":"2014-04-07T12:46:42","date_gmt":"2014-04-07T12:46:42","guid":{"rendered":"https:\/\/gosqeng.test\/?p=545"},"modified":"2019-11-28T12:12:54","modified_gmt":"2019-11-28T12:12:54","slug":"node-js-error-handling-callbacks-vs-promises","status":"publish","type":"post","link":"https:\/\/www.gosquared.com\/blog\/node-js-error-handling-callbacks-vs-promises","title":{"rendered":"Error handling in Node.js"},"content":{"rendered":"<p>Error handling can be a drag, but it&#8217;s essential for the stability of your app. Naturally, I&#8217;m interested in ways to streamline the error handling process to make it as stable as it can be for the app whilst also being convenient for me to write.<\/p>\n<p>Lately, I&#8217;ve been reading a lot about new features in ES6, such as generators, and that&#8217;s led me onto promises, an alternative method of asynchronous flow control to callbacks. I decided to look into the differences in how these different methods approach error handling, their strengths and weaknesses.<\/p>\n<h2>I\/O errors: callbacks vs promises<\/h2>\n<p>The main kind of errors we&#8217;re looking at here are I\/O errors in asynchronous operations. These occur when an I\/O operation fails to yield the expected results, sometimes due to some external problem outside of your program&#8217;s control. For example, we might be fetching data from a MySQL database, but our query contains an error:<\/p>\n<pre><code class=\"language-javascript\">\n\/\/ We misspell 'SELECT' in this query so it fails\nvar query = 'SLECT 1 + 1';\ncon.query(query, function(err){\n  \/\/ query failed. what do we do now?\n});\n<\/code><\/pre>\n<h3>Callbacks<\/h3>\n<p>Notice that in this example we are using Node&#8217;s default style of using a callback to handle the result of the I\/O. The first argument of the callback function is <code>err<\/code>. This is the standard convention in Node, the one you should follow when writing your own async functions.<\/p>\n<p><strong>The first argument to callbacks should always be <code>err<\/code><\/strong><\/p>\n<p>Developers new to Node sometimes forget to follow this convention which makes it very frustrating for other developers trying to work with their code, because they have no consistent point of reference to check whether the operation succeeded or not. But if the first parameter to our callback is reserved for errors then they can be checked before processing the results of each callback.<\/p>\n<p>If <code>err<\/code> is falsy (usually null), then the callback can carry on assuming the operation succeeded. Otherwise, it can deal with the error in an appropriate way, such as logging it along with any contextual information. It can then decide whether or not to carry on depending on the severity of the error or whether or not the resultant data is required to continue operation.<\/p>\n<p>Let&#8217;s implement some error handling for our query error:<\/p>\n<pre><code class=\"language-javascript\">\nvar log = console.log;\n\/\/ We misspell 'SELECT' in this query so it fails\nvar query = 'SLECT 1 + 1';\ncon.query(query, function(err){\n  if (err) return log(\"Query failed. Error: %s. Query: %s\", err, query);\n});\n<\/code><\/pre>\n<p>Here, we check if <code>err<\/code> is present. If it is, we log the error and the query that triggered it then return from the function, stopping it from running any further.<\/p>\n<p><strong>Parallelism<\/strong><\/p>\n<p>You might have a collection of multiple async operations executing in parallel. How do we handle errors in any of those?<\/p>\n<p>Our favourite library for asynchronous flow control is <a href=\"https:\/\/github.com\/caolan\/async\" target=\"_blank\" rel=\"noopener noreferrer\">async<\/a>. Both <code>async.parallel<\/code> and <code>async.series<\/code> accept a collection of operations, and if any of them pass an error to its callback, async will immediately invoke your completion callback with the error:<\/p>\n<pre><code class=\"language-javascript\">\nvar async = require('async');\nvar log = console.log;\nvar op1 = function(cb) {\n  \/\/ We misspell 'SELECT' in this query so it fails\n  var query = 'SLECT 1 + 1';\n  con.query(query, cb);\n}\n\nvar op2 = function(cb) {\n  \/\/ This query is fine\n  con.query('SELECT 1 + 1', cb);\n}\n\nvar ops = [op1, op2];\n\nasync.parallel(ops, function(err, results) {\n  if (err) return log(\"Something went wrong in one of our ops. Err: %s\", err);\n\n  \/\/ Otherwise, process results\n});\n<\/code><\/pre>\n<p><code>async.parallel<\/code> will execute both <code>op1<\/code> and <code>op2<\/code> in parallel but if either or both fail it will invoke our completion callback with the error that occurred first.<\/p>\n<p>Standard callbacks are all well and good when we&#8217;re following Node&#8217;s convention, but it&#8217;s a little bit laborious to check the result of every operation, and this can quickly get messy when there are many nested callbacks each with their own error handling code.<\/p>\n<h3>Promises<\/h3>\n<p>Promises are an alternative to callbacks for asynchronous control flow. They are viewed as a solution to the &#8220;pyramid of doom&#8221; indentation caused by nested callbacks, but they also have some useful error handling features.<\/p>\n<p><a href=\"https:\/\/github.com\/kriskowal\/q\" target=\"_blank\" rel=\"noopener noreferrer\">Q<\/a> is a popular module to get you working with promises. In its <a href=\"https:\/\/github.com\/kriskowal\/q\" target=\"_blank\" rel=\"noopener noreferrer\">README<\/a>, Q describes the concept of promises:<\/p>\n<blockquote><p>If a function cannot return a value or throw an exception without blocking, it can return a promise instead. A promise is an object that represents the return value or the thrown exception that the function may eventually provide.<\/p><\/blockquote>\n<p>Promises allow us to chain operations together in a sequential manner, without the need for nesting. They also neatly encapsulate any results and errors raised within the chain. For example:<\/p>\n<pre><code class=\"language-javascript\">\nvar Q = require('Q');\n\nQ.fcall(op1)\n.then(op2)\n.catch(function(err) {\n  \/\/ An exception was thrown in any of the ops\n  log(\"Something went wrong\");\n})\n.done();\n\n<\/code><\/pre>\n<p>Compare this to the callback-based equivalent:<\/p>\n<pre><code class=\"language-javascript\">\n\nop1(function(err) {\n  if (err) {\n    return log('Something went wrong');\n  }\n\n  op2(function(err) {\n    if (err) {\n      return log('Something else went wrong');\n    }\n  });\n});\n\n<\/code><\/pre>\n<p><strong>&#x2714; Clear &amp; compact<\/strong><\/p>\n<p>The promises method is much more compact, clearer and quicker to write. If an error or exception occurs within any of the ops it is handled by the single <code>.catch()<\/code> handler. Having this single place to handle all errors means you don&#8217;t need to write error checking for each stage of the work.<\/p>\n<p><strong>&#x2714; Exception handling<\/strong><\/p>\n<p>Additionally, the promise chain has more robust protection against exceptions and runtime errors that could be thrown within operations. If an exception is thrown, it will be caught by your <code>.catch()<\/code> handler, or any intermediary error handlers passed to each <code>.then<\/code> step. In contrast, the callback method would crash the node process because it doesn&#8217;t encapsulate exceptions thrown in I\/O callbacks. Catching exceptions like this allows you to gracefully handle the error in an appropriate way instead of crashing the process straight away.<\/p>\n<p><strong>&#x2714; Better stack traces<\/strong><\/p>\n<p>Furthermore, you can use Q&#8217;s <a href=\"https:\/\/github.com\/kriskowal\/q#long-stack-traces\" target=\"_blank\" rel=\"noopener noreferrer\">long stack support<\/a> to get more helpful stack traces that keep track of the call stack across asynchronous operations.<\/p>\n<p><strong>\u2718 Compatibility<\/strong><\/p>\n<p>One slight disadvantage of promises is that in order to use them, you need to make any normal node callback-style code compatible with promise flow control. This usually involves passing the functions through an adapter to make it compatible with promises, such as Q&#8217;s <code>Q.denodify(fn)<\/code>.<\/p>\n<h2>Error events<\/h2>\n<p>We&#8217;ve spoken a lot about I\/O errors during asynchronous flow control, but Node.js has another way of running handlers asynchronously: events.<\/p>\n<p>In Node, an object can be made into an event emitter by inheriting the EventEmitter on its prototype. All core node modules that emit events such as <code>net.Socket<\/code> or <code>http.Server<\/code> inherit from EventEmitter.<\/p>\n<p><strong>The special &#8216;error&#8217; event<\/strong><\/p>\n<p>When an event emitter encounters an error (e.g. a TCP socket abruptly disconnects), it will emit a special &#8216;error&#8217; event. The &#8216;error&#8217; event is special in Node because if there are no listeners on the event emitter for this event then the event emitter will throw an exception and this will crash the process.<\/p>\n<h3>Handling uncaught exceptions<\/h3>\n<p>You might be tempted to prevent exceptions being thrown by binding a listener to the &#8216;error&#8217; event and logging it instead of crashing. This is potentially dangerous, because you usually can&#8217;t guarantee exactly where the error originated from and what all the consequences of it are. Usually the best thing to do is catch the error, log it, close any existing connections and gracefully restart your app.<\/p>\n<p><strong>Do not use <code>process.on('uncaughtException')<\/code><\/strong><\/p>\n<p><a href=\"http:\/\/nodejs.org\/api\/process.html#process_event_uncaughtexception\" target=\"_blank\" rel=\"noopener noreferrer\"><code>process.on('uncaughtException')<\/code><\/a> was added to node for the purpose of catching errors and doing cleanup before the node process exits. Beware! This has quickly become an anti-pattern in Node. It loses the context of the exception, and is prone to hanging if your event handler doesn&#8217;t call <code>process.exit()<\/code>.<\/p>\n<p><strong>Domains<\/strong><\/p>\n<p><a href=\"http:\/\/nodejs.org\/api\/domain.html\" target=\"_blank\" rel=\"noopener noreferrer\">Domains<\/a> were created as a more official way of capturing uncaught exceptions or stray &#8216;error&#8217; events before they get to crash the process.<\/p>\n<p>While the domains API is still in unstable state and is subject to some criticism, it is still better than using <code>process.on('uncaughtException')<\/code>. <a href=\"http:\/\/nodejs.org\/api\/domain.html\" target=\"_blank\" rel=\"noopener noreferrer\">Read the docs<\/a> for usage info.<\/p>\n<h3><em style=\"font-size: 14px; line-height: 1.5em;\">Further reading on <a href=\"https:\/\/github.com\/kriskowal\/q\">Q module<\/a> and <a href=\"http:\/\/nodejs.org\/api\/domain.html\">domains documentation<\/a>.\u00a0<\/em><\/h3>\n<p><em><strong> <a href=\"http:\/\/nodejs.org\/api\/domain.html\" target=\"_blank\" rel=\"noopener noreferrer\"><br \/>\n<\/a><\/strong><\/em><\/p>\n","protected":false},"excerpt":{"rendered":"<p>Error handling can be a drag, but it&#8217;s essential for the stability of your app. Naturally, I&#8217;m interested in ways&#8230;<\/p>\n","protected":false},"author":2,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[1452],"tags":[325],"class_list":["post-545","post","type-post","status-publish","format-standard","hentry","category-engineering","tag-error"],"yoast_head":"<!-- This site is optimized with the Yoast SEO Premium plugin v18.6 (Yoast SEO v19.0) - https:\/\/yoast.com\/wordpress\/plugins\/seo\/ -->\n<title>Error handling in Node.js - GoSquared Blog<\/title>\n<meta name=\"description\" content=\"Exploring error handling methods for Node.js apps\" \/>\n<meta name=\"robots\" content=\"index, follow, max-snippet:-1, max-image-preview:large, max-video-preview:-1\" \/>\n<link rel=\"canonical\" href=\"https:\/\/www.gosquared.com\/blog\/node-js-error-handling-callbacks-vs-promises\" \/>\n<meta property=\"og:locale\" content=\"en_US\" \/>\n<meta property=\"og:type\" content=\"article\" \/>\n<meta property=\"og:title\" content=\"Error handling in Node.js\" \/>\n<meta property=\"og:description\" content=\"Exploring error handling methods for Node.js apps\" \/>\n<meta property=\"og:url\" content=\"https:\/\/www.gosquared.com\/blog\/node-js-error-handling-callbacks-vs-promises\" \/>\n<meta property=\"og:site_name\" content=\"GoSquared Blog\" \/>\n<meta property=\"article:publisher\" content=\"https:\/\/www.facebook.com\/GoSquared\" \/>\n<meta property=\"article:published_time\" content=\"2014-04-07T12:46:42+00:00\" \/>\n<meta property=\"article:modified_time\" content=\"2019-11-28T12:12:54+00:00\" \/>\n<meta name=\"twitter:card\" content=\"summary_large_image\" \/>\n<meta name=\"twitter:creator\" content=\"@TheDeveloper\" \/>\n<meta name=\"twitter:site\" content=\"@GoSquared\" \/>\n<meta name=\"twitter:label1\" content=\"Written by\" \/>\n\t<meta name=\"twitter:data1\" content=\"Geoff Wagstaff\" \/>\n\t<meta name=\"twitter:label2\" content=\"Est. reading time\" \/>\n\t<meta name=\"twitter:data2\" content=\"7 minutes\" \/>\n<script type=\"application\/ld+json\" class=\"yoast-schema-graph\">{\"@context\":\"https:\/\/schema.org\",\"@graph\":[{\"@type\":\"Organization\",\"@id\":\"https:\/\/www.gosquared.com\/blog\/#organization\",\"name\":\"GoSquared\",\"url\":\"https:\/\/www.gosquared.com\/blog\/\",\"sameAs\":[\"https:\/\/instagram.com\/gosquaredteam\",\"https:\/\/www.linkedin.com\/company\/go-squared-ltd.\",\"https:\/\/www.facebook.com\/GoSquared\",\"https:\/\/twitter.com\/GoSquared\"],\"logo\":{\"@type\":\"ImageObject\",\"inLanguage\":\"en-US\",\"@id\":\"https:\/\/www.gosquared.com\/blog\/#\/schema\/logo\/image\/\",\"url\":\"https:\/\/www.gosquared.com\/blog\/wp-content\/uploads\/2015\/07\/gosquared.png\",\"contentUrl\":\"https:\/\/www.gosquared.com\/blog\/wp-content\/uploads\/2015\/07\/gosquared.png\",\"width\":1270,\"height\":250,\"caption\":\"GoSquared\"},\"image\":{\"@id\":\"https:\/\/www.gosquared.com\/blog\/#\/schema\/logo\/image\/\"}},{\"@type\":\"WebSite\",\"@id\":\"https:\/\/www.gosquared.com\/blog\/#website\",\"url\":\"https:\/\/www.gosquared.com\/blog\/\",\"name\":\"GoSquared Blog\",\"description\":\"Turn visitors into customers.\",\"publisher\":{\"@id\":\"https:\/\/www.gosquared.com\/blog\/#organization\"},\"potentialAction\":[{\"@type\":\"SearchAction\",\"target\":{\"@type\":\"EntryPoint\",\"urlTemplate\":\"https:\/\/www.gosquared.com\/blog\/?s={search_term_string}\"},\"query-input\":\"required name=search_term_string\"}],\"inLanguage\":\"en-US\"},{\"@type\":\"WebPage\",\"@id\":\"https:\/\/www.gosquared.com\/blog\/node-js-error-handling-callbacks-vs-promises#webpage\",\"url\":\"https:\/\/www.gosquared.com\/blog\/node-js-error-handling-callbacks-vs-promises\",\"name\":\"Error handling in Node.js - GoSquared Blog\",\"isPartOf\":{\"@id\":\"https:\/\/www.gosquared.com\/blog\/#website\"},\"datePublished\":\"2014-04-07T12:46:42+00:00\",\"dateModified\":\"2019-11-28T12:12:54+00:00\",\"description\":\"Exploring error handling methods for Node.js apps\",\"breadcrumb\":{\"@id\":\"https:\/\/www.gosquared.com\/blog\/node-js-error-handling-callbacks-vs-promises#breadcrumb\"},\"inLanguage\":\"en-US\",\"potentialAction\":[{\"@type\":\"ReadAction\",\"target\":[\"https:\/\/www.gosquared.com\/blog\/node-js-error-handling-callbacks-vs-promises\"]}]},{\"@type\":\"BreadcrumbList\",\"@id\":\"https:\/\/www.gosquared.com\/blog\/node-js-error-handling-callbacks-vs-promises#breadcrumb\",\"itemListElement\":[{\"@type\":\"ListItem\",\"position\":1,\"name\":\"Home\",\"item\":\"https:\/\/www.gosquared.com\/blog\"},{\"@type\":\"ListItem\",\"position\":2,\"name\":\"Error handling in Node.js\"}]},{\"@type\":\"Article\",\"@id\":\"https:\/\/www.gosquared.com\/blog\/node-js-error-handling-callbacks-vs-promises#article\",\"isPartOf\":{\"@id\":\"https:\/\/www.gosquared.com\/blog\/node-js-error-handling-callbacks-vs-promises#webpage\"},\"author\":{\"@id\":\"https:\/\/www.gosquared.com\/blog\/#\/schema\/person\/56a3341790c8a0603f96066fb8d42448\"},\"headline\":\"Error handling in Node.js\",\"datePublished\":\"2014-04-07T12:46:42+00:00\",\"dateModified\":\"2019-11-28T12:12:54+00:00\",\"mainEntityOfPage\":{\"@id\":\"https:\/\/www.gosquared.com\/blog\/node-js-error-handling-callbacks-vs-promises#webpage\"},\"wordCount\":1151,\"commentCount\":1,\"publisher\":{\"@id\":\"https:\/\/www.gosquared.com\/blog\/#organization\"},\"keywords\":[\"Error\"],\"articleSection\":[\"Engineering\"],\"inLanguage\":\"en-US\",\"potentialAction\":[{\"@type\":\"CommentAction\",\"name\":\"Comment\",\"target\":[\"https:\/\/www.gosquared.com\/blog\/node-js-error-handling-callbacks-vs-promises#respond\"]}]},{\"@type\":\"Person\",\"@id\":\"https:\/\/www.gosquared.com\/blog\/#\/schema\/person\/56a3341790c8a0603f96066fb8d42448\",\"name\":\"Geoff Wagstaff\",\"image\":{\"@type\":\"ImageObject\",\"inLanguage\":\"en-US\",\"@id\":\"https:\/\/www.gosquared.com\/blog\/#\/schema\/person\/image\/\",\"url\":\"https:\/\/secure.gravatar.com\/avatar\/66792d2e4d04406697b9a5f322664691590a386bc15b7146d143bbca07aa8889?s=96&d=mm&r=g\",\"contentUrl\":\"https:\/\/secure.gravatar.com\/avatar\/66792d2e4d04406697b9a5f322664691590a386bc15b7146d143bbca07aa8889?s=96&d=mm&r=g\",\"caption\":\"Geoff Wagstaff\"},\"sameAs\":[\"https:\/\/twitter.com\/TheDeveloper\"],\"url\":\"https:\/\/www.gosquared.com\/blog\/author\/echo\"}]}<\/script>\n<!-- \/ Yoast SEO Premium plugin. -->","yoast_head_json":{"title":"Error handling in Node.js - GoSquared Blog","description":"Exploring error handling methods for Node.js apps","robots":{"index":"index","follow":"follow","max-snippet":"max-snippet:-1","max-image-preview":"max-image-preview:large","max-video-preview":"max-video-preview:-1"},"canonical":"https:\/\/www.gosquared.com\/blog\/node-js-error-handling-callbacks-vs-promises","og_locale":"en_US","og_type":"article","og_title":"Error handling in Node.js","og_description":"Exploring error handling methods for Node.js apps","og_url":"https:\/\/www.gosquared.com\/blog\/node-js-error-handling-callbacks-vs-promises","og_site_name":"GoSquared Blog","article_publisher":"https:\/\/www.facebook.com\/GoSquared","article_published_time":"2014-04-07T12:46:42+00:00","article_modified_time":"2019-11-28T12:12:54+00:00","twitter_card":"summary_large_image","twitter_creator":"@TheDeveloper","twitter_site":"@GoSquared","twitter_misc":{"Written by":"Geoff Wagstaff","Est. reading time":"7 minutes"},"schema":{"@context":"https:\/\/schema.org","@graph":[{"@type":"Organization","@id":"https:\/\/www.gosquared.com\/blog\/#organization","name":"GoSquared","url":"https:\/\/www.gosquared.com\/blog\/","sameAs":["https:\/\/instagram.com\/gosquaredteam","https:\/\/www.linkedin.com\/company\/go-squared-ltd.","https:\/\/www.facebook.com\/GoSquared","https:\/\/twitter.com\/GoSquared"],"logo":{"@type":"ImageObject","inLanguage":"en-US","@id":"https:\/\/www.gosquared.com\/blog\/#\/schema\/logo\/image\/","url":"https:\/\/www.gosquared.com\/blog\/wp-content\/uploads\/2015\/07\/gosquared.png","contentUrl":"https:\/\/www.gosquared.com\/blog\/wp-content\/uploads\/2015\/07\/gosquared.png","width":1270,"height":250,"caption":"GoSquared"},"image":{"@id":"https:\/\/www.gosquared.com\/blog\/#\/schema\/logo\/image\/"}},{"@type":"WebSite","@id":"https:\/\/www.gosquared.com\/blog\/#website","url":"https:\/\/www.gosquared.com\/blog\/","name":"GoSquared Blog","description":"Turn visitors into customers.","publisher":{"@id":"https:\/\/www.gosquared.com\/blog\/#organization"},"potentialAction":[{"@type":"SearchAction","target":{"@type":"EntryPoint","urlTemplate":"https:\/\/www.gosquared.com\/blog\/?s={search_term_string}"},"query-input":"required name=search_term_string"}],"inLanguage":"en-US"},{"@type":"WebPage","@id":"https:\/\/www.gosquared.com\/blog\/node-js-error-handling-callbacks-vs-promises#webpage","url":"https:\/\/www.gosquared.com\/blog\/node-js-error-handling-callbacks-vs-promises","name":"Error handling in Node.js - GoSquared Blog","isPartOf":{"@id":"https:\/\/www.gosquared.com\/blog\/#website"},"datePublished":"2014-04-07T12:46:42+00:00","dateModified":"2019-11-28T12:12:54+00:00","description":"Exploring error handling methods for Node.js apps","breadcrumb":{"@id":"https:\/\/www.gosquared.com\/blog\/node-js-error-handling-callbacks-vs-promises#breadcrumb"},"inLanguage":"en-US","potentialAction":[{"@type":"ReadAction","target":["https:\/\/www.gosquared.com\/blog\/node-js-error-handling-callbacks-vs-promises"]}]},{"@type":"BreadcrumbList","@id":"https:\/\/www.gosquared.com\/blog\/node-js-error-handling-callbacks-vs-promises#breadcrumb","itemListElement":[{"@type":"ListItem","position":1,"name":"Home","item":"https:\/\/www.gosquared.com\/blog"},{"@type":"ListItem","position":2,"name":"Error handling in Node.js"}]},{"@type":"Article","@id":"https:\/\/www.gosquared.com\/blog\/node-js-error-handling-callbacks-vs-promises#article","isPartOf":{"@id":"https:\/\/www.gosquared.com\/blog\/node-js-error-handling-callbacks-vs-promises#webpage"},"author":{"@id":"https:\/\/www.gosquared.com\/blog\/#\/schema\/person\/56a3341790c8a0603f96066fb8d42448"},"headline":"Error handling in Node.js","datePublished":"2014-04-07T12:46:42+00:00","dateModified":"2019-11-28T12:12:54+00:00","mainEntityOfPage":{"@id":"https:\/\/www.gosquared.com\/blog\/node-js-error-handling-callbacks-vs-promises#webpage"},"wordCount":1151,"commentCount":1,"publisher":{"@id":"https:\/\/www.gosquared.com\/blog\/#organization"},"keywords":["Error"],"articleSection":["Engineering"],"inLanguage":"en-US","potentialAction":[{"@type":"CommentAction","name":"Comment","target":["https:\/\/www.gosquared.com\/blog\/node-js-error-handling-callbacks-vs-promises#respond"]}]},{"@type":"Person","@id":"https:\/\/www.gosquared.com\/blog\/#\/schema\/person\/56a3341790c8a0603f96066fb8d42448","name":"Geoff Wagstaff","image":{"@type":"ImageObject","inLanguage":"en-US","@id":"https:\/\/www.gosquared.com\/blog\/#\/schema\/person\/image\/","url":"https:\/\/secure.gravatar.com\/avatar\/66792d2e4d04406697b9a5f322664691590a386bc15b7146d143bbca07aa8889?s=96&d=mm&r=g","contentUrl":"https:\/\/secure.gravatar.com\/avatar\/66792d2e4d04406697b9a5f322664691590a386bc15b7146d143bbca07aa8889?s=96&d=mm&r=g","caption":"Geoff Wagstaff"},"sameAs":["https:\/\/twitter.com\/TheDeveloper"],"url":"https:\/\/www.gosquared.com\/blog\/author\/echo"}]}},"wps_subtitle":"Exploring error handling methods for Node.js apps","_links":{"self":[{"href":"https:\/\/www.gosquared.com\/blog\/wp-json\/wp\/v2\/posts\/545","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/www.gosquared.com\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/www.gosquared.com\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/www.gosquared.com\/blog\/wp-json\/wp\/v2\/users\/2"}],"replies":[{"embeddable":true,"href":"https:\/\/www.gosquared.com\/blog\/wp-json\/wp\/v2\/comments?post=545"}],"version-history":[{"count":0,"href":"https:\/\/www.gosquared.com\/blog\/wp-json\/wp\/v2\/posts\/545\/revisions"}],"wp:attachment":[{"href":"https:\/\/www.gosquared.com\/blog\/wp-json\/wp\/v2\/media?parent=545"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.gosquared.com\/blog\/wp-json\/wp\/v2\/categories?post=545"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.gosquared.com\/blog\/wp-json\/wp\/v2\/tags?post=545"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}