<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Jordan Leal-Walker</title>
    <description>The latest articles on DEV Community by Jordan Leal-Walker (@jordanleal12).</description>
    <link>https://dev.to/jordanleal12</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F2975293%2F3d0b3402-69a4-441b-8a72-933ed47a4fb4.jpg</url>
      <title>DEV Community: Jordan Leal-Walker</title>
      <link>https://dev.to/jordanleal12</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/jordanleal12"/>
    <language>en</language>
    <item>
      <title>The Dog Exposed My Stacktrace! 😱 My Bespoke Solution to a Common API Security Issue</title>
      <dc:creator>Jordan Leal-Walker</dc:creator>
      <pubDate>Wed, 10 Dec 2025 04:31:44 +0000</pubDate>
      <link>https://dev.to/jordanleal12/the-dog-exposed-my-stacktrace-my-bespoke-solution-to-a-common-api-security-issue-3b53</link>
      <guid>https://dev.to/jordanleal12/the-dog-exposed-my-stacktrace-my-bespoke-solution-to-a-common-api-security-issue-3b53</guid>
      <description>&lt;p&gt;As someone who recently built a MERN stack backend, I was reminded of what every developer who has worked on the same already knows - catching and handling errors safely is a pain. This article seeks to cover the following:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;❗ Problems faced by developers implementing error handling in a MERN backend&lt;/li&gt;
&lt;li&gt;🔧 How other resources have addressed this problem&lt;/li&gt;
&lt;li&gt;📦 The lightweight NPM package I built to help address it&lt;/li&gt;
&lt;li&gt;⚖️ The industry relevant ethical and technical issues relating to this problem&lt;/li&gt;
&lt;li&gt;📝 My planning process behind building the package and the tools chosen&lt;/li&gt;
&lt;li&gt;🌱 How this project helped me grow as a developer&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;If you've ever wished there was an easier, safer way to implement error handling middleware in your MERN backend, read on to see my answer to this common problem!&lt;/p&gt;

&lt;h2&gt;
  
  
  Contents
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;The Problem&lt;/li&gt;
&lt;li&gt;Ethical Concerns&lt;/li&gt;
&lt;li&gt;Relevant Industry Trends&lt;/li&gt;
&lt;li&gt;How Has This Problem Already Been Addressed?&lt;/li&gt;
&lt;li&gt;My Solution&lt;/li&gt;
&lt;li&gt;Project Planning&lt;/li&gt;
&lt;li&gt;Skills, Technologies, Languages &amp;amp; Frameworks&lt;/li&gt;
&lt;li&gt;How This Project Improved My Skills&lt;/li&gt;
&lt;li&gt;What Could I Do Differently In The Future?&lt;/li&gt;
&lt;li&gt;Conclusion&lt;/li&gt;
&lt;li&gt;References&lt;/li&gt;
&lt;/ol&gt;




&lt;h2&gt;
  
  
  The Problem
&lt;/h2&gt;

&lt;p&gt;Errors happen. That means when writing your routes in your API, you need to ensure they're handled gracefully, catching and responding to the error so the client gets a meaningful message rather than an unexplained crash. Most peoples first foray into catching and responding to an error in a route may have looked something like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// ❌ BAD PRACTICE - No centralized error handling, exposing stack to client&lt;/span&gt;
&lt;span class="nx"&gt;app&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;movies/:imdbId&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;async &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;request&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;response&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;try&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="cm"&gt;/* Route logic */&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;catch &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;error&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Error occurred:&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;error&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; &lt;span class="c1"&gt;// ❌ Logging the entire error object to the console&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;response&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;status&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;500&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;json&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
      &lt;span class="na"&gt;success&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="na"&gt;message&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;An error occurred while fetching movie&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="nx"&gt;error&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="c1"&gt;// ❌ Leaking the stack trace to the client!&lt;/span&gt;
    &lt;span class="p"&gt;});&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now, hopefully to most of you it's immediately obvious what's wrong with this picture, and for those that it isn't, don't worry! We'll go through it:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;No Centralized Error Handling:&lt;/strong&gt; Without a centralized error handler, each route either has to individually account for every expected error type, or return a generic, unhelpful response to the client&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Sending whole error object to the client:&lt;/strong&gt; There is one particularly good reason to never send your full error object to the client - stack traces! Not only will this bury your response data in an avalanche of information, that information can contain information that attackers can use to help mount attacks (internal file paths, database query details, configuration values etc).&lt;sup id="fnref1"&gt;1&lt;/sup&gt; Errors should be reformatted into safe, consistent responses before sending to the client.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Logging the whole error object:&lt;/strong&gt; Many developers think that logging full error objects server side is safe, after all these logs aren't exposed to the client right? Well, not according to most leading industry voices in security. For example, the OWASP 'Logging Cheat Sheet'&lt;sup id="fnref2"&gt;2&lt;/sup&gt; explicitly states to remove, mask, sanitize or encrypt sensitive data from logs - and for good reason. If attackers ever gain access to logs, they can use the sensitive data within to expedite further attacks. &lt;a href="https://www.hackerone.com/blog/logging-silent-security-guard-and-its-pitfalls" rel="noopener noreferrer"&gt;This article by HackerOne&lt;/a&gt;&lt;sup id="fnref3"&gt;3&lt;/sup&gt; is a useful resource for those wanting to better understand the security issues related to logging.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;An example of a (sanitized for security) full error object, including stack trace from the above code:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;Error occurred: ValidationError: Movie validation failed: title: &lt;span class="s2"&gt;"Path &lt;/span&gt;&lt;span class="sb"&gt;`&lt;/span&gt;title&lt;span class="sb"&gt;`&lt;/span&gt;&lt;span class="s2"&gt; is required."&lt;/span&gt;
    at /sanitized/path/controllers/MovieController.js:28:40
    at Layer.handle &lt;span class="o"&gt;[&lt;/span&gt;as handle_request] &lt;span class="o"&gt;(&lt;/span&gt;/sanitized/path/express/lib/router/layer.js:95:5&lt;span class="o"&gt;)&lt;/span&gt;
    at next &lt;span class="o"&gt;(&lt;/span&gt;/sanitized/path/express/lib/router/route.js:144:13&lt;span class="o"&gt;)&lt;/span&gt;
    at /sanitized/path/utils/auth.js:45:22
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The solution to this problem is creating a centralized error handling middleware, something like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// utils/errorHandler.js&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;errorHandler&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;req&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;next&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;error&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;The following error occurred:&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;name&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;code&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;code&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;message&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;message&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="p"&gt;});&lt;/span&gt;

  &lt;span class="c1"&gt;// Catch MongoDB validation errors&lt;/span&gt;
  &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;name&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;ValidationError&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;status&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;400&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;json&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
      &lt;span class="na"&gt;success&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="na"&gt;message&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Schema validation failed&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="c1"&gt;// Map over each error to return array of error messages&lt;/span&gt;
      &lt;span class="na"&gt;errors&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;Object&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;values&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;errors&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;map&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;e&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;e&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;message&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
    &lt;span class="p"&gt;});&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="c1"&gt;// Additional 'if' blocks to catch every type of expected error&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Allowing us to simplify our route from before (and all our other routes) to the following:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="nx"&gt;app&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;movies/:imdbId&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;async &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;request&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;response&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;next&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;try&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="cm"&gt;/* Route logic */&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;catch &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;error&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nf"&gt;next&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;error&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; &lt;span class="c1"&gt;// Passes error to error-handling middleware&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Problem solved right? Well, not quite. I provided a single example of an error catching &lt;code&gt;if&lt;/code&gt; block in the errorHandler middleware, but in actuality you'll need alot more than one block. Setting up a robust error handling middleware involves doing the following:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Identify the errors (including third party library) errors your middleware needs to catch&lt;/li&gt;
&lt;li&gt;Research common/expected error response structures&lt;/li&gt;
&lt;li&gt;Understand the shape of each error being caught so it can be formatted consistently for the client (each library has its own error object structure)&lt;/li&gt;
&lt;li&gt;Setup error logging&lt;/li&gt;
&lt;li&gt;Change logging settings between environments (often we wish to see stack traces in development for debugging, but not in production)&lt;/li&gt;
&lt;li&gt;Ensure we aren't catching errors that SHOULDN'T be caught&lt;/li&gt;
&lt;li&gt;Writing tests to ensure middleware catches and formats errors as expected&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;And you have to set that up every time you make a new MERN backend! As you can see, there's alot of room for error. What if you add the error stack to your log during development and forget to turn it off for production? Or a slight difference in response format for one error causes an unexpected bug for the client?&lt;/p&gt;

&lt;p&gt;Rather than dealing with this each time, I devised my own simple, lightweight package as an easy solution. But first, let's look at the ethical issues associated with this problem, how it relates to current industry trends, and approaches other people have made to address this.&lt;/p&gt;




&lt;h2&gt;
  
  
  Ethical Concerns
&lt;/h2&gt;

&lt;p&gt;The &lt;a href="https://www.acm.org/code-of-ethics" rel="noopener noreferrer"&gt;ACM Code of Ethics&lt;/a&gt;&lt;sup id="fnref4"&gt;4&lt;/sup&gt; is a globally recognized industry standard for ethics among software engineers. Section 2.9 states it is the responsibility of computing professionals to 'Design and implement systems that are robustly and usably secure.'&lt;/p&gt;

&lt;p&gt;Another trusted ethics standard, &lt;a href="https://www.computer.org/education/code-of-ethics" rel="noopener noreferrer"&gt;IEEE-CS Code of Ethics&lt;/a&gt;&lt;sup id="fnref5"&gt;5&lt;/sup&gt; 1.03. states: "Approve software only if they have a well-founded belief that it is safe, meets specifications, passes appropriate tests, and does not diminish quality of life, diminish privacy or harm the environment. The ultimate effect of the work should be to the public good."&lt;/p&gt;

&lt;p&gt;We discussed the potential security risks and problems associated with incorrect error handling above, but how relevant is it actually to our industry? Let's have a look at some of the latest industry data to see.&lt;/p&gt;

&lt;p&gt;Salt's latest 'State of API Security Report 2025'.&lt;sup id="fnref6"&gt;6&lt;/sup&gt; lists some troubling statistics:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;99% of surveyed organizations say they've encountered API security issues in the past year&lt;/li&gt;
&lt;li&gt;55% say they've slowed the rollout of an application due to API security concerns&lt;/li&gt;
&lt;li&gt;34% discovered they were exposing sensitive date through their API's (and that's only the ones that caught it!)&lt;/li&gt;
&lt;li&gt;54% of attacks fell under OWASP's 'API Security Top Ten - #5 Security Misconfiguration'&lt;sup id="fnref7"&gt;7&lt;/sup&gt;, the description of which includes: "Error handling reveals stack traces or other overly informative error messages to users."&lt;/li&gt;
&lt;li&gt;30% of organizations reported a 51-100% growth in the number of API's managed over the past year&lt;/li&gt;
&lt;li&gt;25% experienced growth of API's managed exceeding 100%&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;As you can see, not only is this exact issue extremely relevant in our industry currently, the explosive growth of API usage means it's becoming increasingly relevant over time. It is accordingly the ethical responsibility of any developer working with API's to have a safe, robust and reliable strategy for implementing error handling within their application.&lt;/p&gt;




&lt;h2&gt;
  
  
  Relevant Industry Trends
&lt;/h2&gt;

&lt;p&gt;We already covered the explosive industry growth in API usage, by why does this article and my bespoke package focus on a MERN backend specifically? What other emerging trends effected my decisions in building this package?&lt;/p&gt;

&lt;h3&gt;
  
  
  MERN stack
&lt;/h3&gt;

&lt;p&gt;Lets take a look at the results of StackOverflow's 2024&lt;sup id="fnref8"&gt;8&lt;/sup&gt; and 2025&lt;sup id="fnref9"&gt;9&lt;/sup&gt; Developer Survey to analyze current industry trends. For the following, we will be looking specifically at the responses of professional developers:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Javascript remains the most popular language, rising from 64.6% in 2024 to 68.8% in 2025&lt;/li&gt;
&lt;li&gt;MongoDb is the second most popular NoSql database, being overtaken by Redis from its first place position in 2024&lt;/li&gt;
&lt;li&gt;Node.js rose to become the most popular web framework/technology, from 40.7% usage in 2024 to 49.1% in 2025&lt;/li&gt;
&lt;li&gt;Express rose from 7th place at 18.2% to 6th place at 20.3%&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fv1qf4cr8hv5nn6y1i164.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fv1qf4cr8hv5nn6y1i164.png" alt="Stack Overflow Survey of programming languages" width="800" height="233"&gt;&lt;/a&gt;&lt;br&gt;
&lt;em&gt;Javascript remains king of the programming languages&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Looking at the Jetbrains' 2025 'State of the Developer Ecosystem'&lt;sup id="fnref10"&gt;10&lt;/sup&gt; we can identify that 48% of functionality being implemented by developers is aimed at 'providing API's and services'.&lt;/p&gt;

&lt;p&gt;The above data paints a clear picture - API creation is in high demand, and the usage of Mongoose/MongoDb, Express and Node.js is not only extremely popular - it's becoming increasingly popular over time. While data on the trends of those platforms being used together is difficult to find, &lt;a href="https://www.sarojdangol012.com.np/blogs/why-mern-stack-dominates-2025" rel="noopener noreferrer"&gt;this blog post&lt;/a&gt;&lt;sup id="fnref11"&gt;11&lt;/sup&gt; claims "MERN stack developers are in high demand, with job postings on platforms like LinkedIn and Indeed showing a 20% year-over-year increase in 2025." (They did not provide a source for their claim).&lt;/p&gt;

&lt;p&gt;So we can see that having robust error handling strategies for the base MERN stack backend is vital, but how about the common third party libraries used alongside them? As previously mentioned, different libraries throw different error shapes, so it's important to know what packages are commonly being used and how to handle them.&lt;/p&gt;
&lt;h3&gt;
  
  
  Popular MERN Packages
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;jsonwebtoken:&lt;/strong&gt; Rising from 62 to 103 million weekly downloads over the last two years, the jsonwebtoken&lt;sup id="fnref12"&gt;12&lt;/sup&gt; package remains the de-facto package for handling authentication in API's.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fnyvl58oay6ouhnd9on4g.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fnyvl58oay6ouhnd9on4g.png" alt="jsonwebtoken package monthly downloads over 2 years" width="800" height="290"&gt;&lt;/a&gt;&lt;br&gt;
&lt;em&gt;Monthly downloads for the jsonwebtoken package over 2 years&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;zod:&lt;/strong&gt; Exploding in popularity to 237 million monthly downloads from only 26 two years ago, it's no exaggeration to say this package&lt;sup id="fnref13"&gt;13&lt;/sup&gt; is one of the industry relevant trends for MERN stack developers in 2025. A runtime validation library, zod validates your data &lt;em&gt;before&lt;/em&gt; saving it to your database, allowing you to catch and validate bad data early. This doesn't replace mongoose, it works hand in hand with it, with mongoose still doing it's final validation upon saving to the database.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fr1xioi9wcalbiiqnff9d.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fr1xioi9wcalbiiqnff9d.png" alt="zod package monthly downloads over 2 years" width="800" height="289"&gt;&lt;/a&gt;&lt;br&gt;
&lt;em&gt;Monthly downloads for the zod package over 2 years&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Logging libraries (e.g. pino):&lt;/strong&gt; Due to the limitations of the native console log, logging packages have become increasingly popular over time. One such example is the hyper-fast pino&lt;sup id="fnref14"&gt;14&lt;/sup&gt; library, rising dramatically in weekly downloads over the last two years to jostle the reigning king winston for first place.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F6vrmcuelc3i9oq268xbm.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F6vrmcuelc3i9oq268xbm.png" alt="pino package monthly downloads over 2 years" width="800" height="296"&gt;&lt;/a&gt;&lt;br&gt;
&lt;em&gt;Monthly downloads for the pino package over 2 years&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;The above data paints a clear picture - your error handling middleware will likely have to deal with errors from the jsonwebtoken and zod packages, and work with third party logging libraries to log errors.&lt;/p&gt;


&lt;h2&gt;
  
  
  How Has This Problem Already Been Addressed?
&lt;/h2&gt;

&lt;p&gt;Lets recap what exactly it is we need to address. We need error handling middleware for a MERN api capable of the following:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Gracefully handling errors from the core MERN backend libraries (Express, Mongoose/MongoDb)&lt;/li&gt;
&lt;li&gt;Gracefully handling errors from the most popular libraries used alongside this stack (jsonwebtoken, zod)&lt;/li&gt;
&lt;li&gt;Formatting of errors into consistent responses for the client regardless of error type&lt;/li&gt;
&lt;li&gt;Integration with third party logging tools&lt;/li&gt;
&lt;li&gt;Configuration options to decide whether to include stack traces in development for debugging, defaulted to not include for safety&lt;/li&gt;
&lt;li&gt;Ability to gracefully catch and respond to custom application errors&lt;/li&gt;
&lt;li&gt;Ability for user to pass additional custom error handlers to handle other library errors&lt;/li&gt;
&lt;li&gt;Catch-all error handler to ensure any unexpected errors are handled gracefully&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Now lets look at the most popular npm packages that overlap our requirements:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;&lt;strong&gt;Package&lt;/strong&gt;&lt;/th&gt;
&lt;th&gt;&lt;strong&gt;Weekly Downloads&lt;/strong&gt;&lt;/th&gt;
&lt;th&gt;&lt;strong&gt;Last Update&lt;/strong&gt;&lt;/th&gt;
&lt;th&gt;&lt;strong&gt;Score&lt;/strong&gt;&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;errorhandler&lt;sup id="fnref15"&gt;15&lt;/sup&gt;
&lt;/td&gt;
&lt;td&gt;~1.6m&lt;/td&gt;
&lt;td&gt;2018&lt;/td&gt;
&lt;td&gt;2/8&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;strong-error-handler&lt;sup id="fnref16"&gt;16&lt;/sup&gt;
&lt;/td&gt;
&lt;td&gt;~44,000&lt;/td&gt;
&lt;td&gt;Nov 2025&lt;/td&gt;
&lt;td&gt;5/8&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;express-error-toolkit&lt;sup id="fnref17"&gt;17&lt;/sup&gt;
&lt;/td&gt;
&lt;td&gt;90&lt;/td&gt;
&lt;td&gt;Nov 2025&lt;/td&gt;
&lt;td&gt;3.5/8&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;error-cure&lt;sup id="fnref18"&gt;18&lt;/sup&gt;
&lt;/td&gt;
&lt;td&gt;3&lt;/td&gt;
&lt;td&gt;Sep 2025&lt;/td&gt;
&lt;td&gt;4/8&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;
&lt;h3&gt;
  
  
  errorhandler
&lt;/h3&gt;

&lt;p&gt;An official package created by the Express.js team, this is designed to be used in development only for debugging. It will catch all errors and format a standardized response, but those responses are not meant for client integration and the package only handles errors when environment is set to 'development'.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;&lt;strong&gt;Requirement&lt;/strong&gt;&lt;/th&gt;
&lt;th&gt;&lt;strong&gt;Is it Addressed?&lt;/strong&gt;&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Specific formatting for core MERN API library errors&lt;/td&gt;
&lt;td&gt;❌ Does not specifically format these errors&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Specific formatting for jsonwebtoken &amp;amp; zod errors&lt;/td&gt;
&lt;td&gt;❌ Does not specifically format these errors&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Formats errors into consistent, client friendly response&lt;/td&gt;
&lt;td&gt;🟡 Formats errors consistently, but not client friendly&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Easy integration with third party logging tools&lt;/td&gt;
&lt;td&gt;❌ No specific integration options with logging tools&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Configurable, env based error &amp;amp; stack trace logging&lt;/td&gt;
&lt;td&gt;🟡 Runs only in development, does not handle errors at all in production&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Gracefully handles custom application errors&lt;/td&gt;
&lt;td&gt;🟡 Will handle in development but not production&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Accepts and integrates custom error handlers&lt;/td&gt;
&lt;td&gt;❌ No integration options with custom error handlers&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Catch-all error handler - no unhandled errors&lt;/td&gt;
&lt;td&gt;🟡 Will catch all errors - but only in development&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;
&lt;h3&gt;
  
  
  strong-error-handler
&lt;/h3&gt;

&lt;p&gt;A solid option for many developer needs, this package is safe out of the box and highly configurable, with configuration options for response format, content type, logging, safe fields etc. However, it does not provide specific error formatting for our database and core third party library errors, nor easy addition/integration of custom error handlers. Excelling in configuration, this library has a relatively steep learning curve, and is accordingly less suitable for more basic/beginner friendly API's.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;&lt;strong&gt;Requirement&lt;/strong&gt;&lt;/th&gt;
&lt;th&gt;&lt;strong&gt;Is it Addressed?&lt;/strong&gt;&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Specific formatting for core MERN API library errors&lt;/td&gt;
&lt;td&gt;❌ Does not specifically format these errors&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Specific formatting for jsonwebtoken &amp;amp; zod errors&lt;/td&gt;
&lt;td&gt;❌ Does not specifically format these errors&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Formats errors into consistent, client friendly response&lt;/td&gt;
&lt;td&gt;✅ Consistent and configurable responses&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Easy integration with third party logging tools&lt;/td&gt;
&lt;td&gt;✅ Readme shows example of how to integrate third party logger&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Configurable, env based error &amp;amp; stack trace logging&lt;/td&gt;
&lt;td&gt;✅ Defaults to exclude stack trace with configurable inclusion options&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Gracefully handles custom application errors&lt;/td&gt;
&lt;td&gt;✅ Handles status codes, headers etc.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Accepts and integrates custom error handlers&lt;/td&gt;
&lt;td&gt;❌ No integration options with custom error handlers&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Catch-all error handler - no unhandled errors&lt;/td&gt;
&lt;td&gt;✅ Yes&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;
&lt;h3&gt;
  
  
  express-error-toolkit
&lt;/h3&gt;

&lt;p&gt;Another great option for error handling middleware, this package offers custom error classes, express middleware, an async error handler, a http error factory function for creating custom errors and a type guard for safe error type checks. Although this package has great documentation, it's still a steep learning curve and doesn't meet our requirements to specifically format our core expected MERN API errors, work with custom loggers, or accept additional custom error handlers.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;&lt;strong&gt;Requirement&lt;/strong&gt;&lt;/th&gt;
&lt;th&gt;&lt;strong&gt;Is it Addressed?&lt;/strong&gt;&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Specific formatting for core MERN API library errors&lt;/td&gt;
&lt;td&gt;❌ Does not specifically format these errors&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Specific formatting for jsonwebtoken &amp;amp; zod errors&lt;/td&gt;
&lt;td&gt;❌ Does not specifically format these errors&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Formats errors into consistent, client friendly response&lt;/td&gt;
&lt;td&gt;✅ Consistent and configurable responses&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Easy integration with third party logging tools&lt;/td&gt;
&lt;td&gt;❌ No specific integration options with logging tools&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Configurable, env based error &amp;amp; stack trace logging&lt;/td&gt;
&lt;td&gt;🟡 Does not log errors in production but default logs stack trace in development&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Gracefully handles custom application errors&lt;/td&gt;
&lt;td&gt;✅ Exceptional custom error creation and handling&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Accepts and integrates custom error handlers&lt;/td&gt;
&lt;td&gt;❌ No integration options with custom error handlers&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Catch-all error handler - no unhandled errors&lt;/td&gt;
&lt;td&gt;✅ Yes&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;
&lt;h3&gt;
  
  
  error-cure
&lt;/h3&gt;

&lt;p&gt;This package comes closest to meeting all our requirements, and upon initial review made me question if I needed to create my own package at all. It's a great, lightweight error handling middleware package with consistent formatting, custom app errors, catch all safety and environment based security.&lt;/p&gt;

&lt;p&gt;However, it still falls short in handling our specific database and third party library errors, requiring wrapping of those errors for specific formatting. There is no obvious integration option for additional custom error handling, or integration with logging tools. Perhaps most importantly, although it uses environment variables to configure error and stack trace logging, these options are only configurable through setting your environment variables, and development still logs stack traces by default.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;&lt;strong&gt;Requirement&lt;/strong&gt;&lt;/th&gt;
&lt;th&gt;&lt;strong&gt;Is it Addressed?&lt;/strong&gt;&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Specific formatting for core MERN API library errors&lt;/td&gt;
&lt;td&gt;❌ Requires manual mapping of database errors&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Specific formatting for jsonwebtoken &amp;amp; zod errors&lt;/td&gt;
&lt;td&gt;❌ Does not specifically format these errors&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Formats errors into consistent, client friendly response&lt;/td&gt;
&lt;td&gt;✅ Consistent and client friendly responses&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Easy integration with third party logging tools&lt;/td&gt;
&lt;td&gt;🟡 Not specifically, but does output error file depending on configuration&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Configurable, env based error &amp;amp; stack trace logging&lt;/td&gt;
&lt;td&gt;🟡 Does not log errors in production but default logs stack trace in development&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Gracefully handles custom application errors&lt;/td&gt;
&lt;td&gt;✅ Exceptional custom error creation and handling&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Accepts and integrates custom error handlers&lt;/td&gt;
&lt;td&gt;❌ No integration options with custom error handlers&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Catch-all error handler - no unhandled errors&lt;/td&gt;
&lt;td&gt;✅ Yes&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;


&lt;h2&gt;
  
  
  My Solution
&lt;/h2&gt;

&lt;p&gt;Enter &lt;code&gt;express-mongo-error-handler&lt;/code&gt;, my &lt;a href="https://www.npmjs.com/package/express-mongo-error-handler/v/1.2.0" rel="noopener noreferrer"&gt;NPM error handling middleware package&lt;/a&gt;&lt;sup id="fnref19"&gt;19&lt;/sup&gt;, created by me to have a package that addressed every need previously mentioned (&lt;a href="https://github.com/jordanleal12/express-mongo-error-handler" rel="noopener noreferrer"&gt;GitHub repository here&lt;/a&gt;&lt;sup id="fnref20"&gt;20&lt;/sup&gt;). This lightweight, easy to use package is compatible with ESM, CommonJs and TypeScript, contains robust and easy to understand documentation, and is ready to use straight out of the box as your error handling middleware in a MERN stack API.&lt;/p&gt;

&lt;p&gt;Lets rehash our previously described problems and desired solutions, and show exactly how this package addresses each of them.&lt;/p&gt;
&lt;h3&gt;
  
  
  1. Gracefully handling errors from the core MERN backend libraries (Express, Mongoose/MongoDb)
&lt;/h3&gt;

&lt;p&gt;This middleware handles core MERN API errors by default, with extremely simple setup.&lt;br&gt;
Setup with default options (logs errors to console.error in development/test only, excludes stack traces):&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;express&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;express&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;createErrorHandler&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;express-mongo-error-handler&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="c1"&gt;// ESM&lt;/span&gt;
&lt;span class="c1"&gt;// OR&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;createErrorHandler&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;require&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;express-mongo-error-handler&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; &lt;span class="c1"&gt;// CJS&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;app&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;express&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

&lt;span class="c1"&gt;// Your routes here&lt;/span&gt;
&lt;span class="nx"&gt;app&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;/api/example&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;req&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="cm"&gt;/* Route logic */&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;

&lt;span class="c1"&gt;// ADD LAST! After all existing middleware and routes.&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;errorHandler&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;createErrorHandler&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="nx"&gt;app&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;use&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;errorHandler&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And lets have a brief look under the hood of the errorHandler middleware:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// Accepts options parameter for configuration&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;createErrorHandler&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;options&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{})&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="c1"&gt;// Check for development or test environment (false without environment variables for safety)&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;notProduction&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;process&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;env&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;NODE_ENV&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;development&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="nx"&gt;process&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;env&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;NODE_ENV&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;test&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

  &lt;span class="c1"&gt;// Set default options with destructuring for configuration&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;logErrors&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;notProduction&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="nx"&gt;exposeStack&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="nx"&gt;logger&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;error&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="nx"&gt;customHandlers&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[],&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;options&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

  &lt;span class="c1"&gt;// Return configured middleware function&lt;/span&gt;
  &lt;span class="k"&gt;return &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;req&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;next&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="cm"&gt;/*
    Logic to handle error logging (shown later)
    */&lt;/span&gt;

    &lt;span class="cm"&gt;/*
    Logic to handle custom error handlers (shown later)
    */&lt;/span&gt;

    &lt;span class="cm"&gt;/* Catch SyntaxError from invalid JSON caught by JSON parsing middleware. Check for 400 and 'body'
    in error so we don't catch other SyntaxErrors by mistake */&lt;/span&gt;
    &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt; &lt;span class="k"&gt;instanceof&lt;/span&gt; &lt;span class="nx"&gt;SyntaxError&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;status&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="mi"&gt;400&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;body&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="k"&gt;in&lt;/span&gt; &lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;status&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;400&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;json&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
        &lt;span class="na"&gt;success&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="na"&gt;message&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Invalid JSON payload in request&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="na"&gt;errors&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;The request body JSON is invalid and could not be parsed&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
      &lt;span class="p"&gt;});&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="c1"&gt;// Request body data is too large (default limit is 100kb)&lt;/span&gt;
    &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;type&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;entity.too.large&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;status&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;413&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;json&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
        &lt;span class="na"&gt;success&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="na"&gt;message&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;JSON payload too large&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="na"&gt;errors&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;The request body data exceeds the maximum size limit&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
      &lt;span class="p"&gt;});&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="cm"&gt;/*
    Additional `if` blocks catch Express, Mongoose/MongoDb, JWT, Zod, Custom App
    errors and unhandled/unexpected errors
    */&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Refer to the &lt;code&gt;index.js&lt;/code&gt; file in the repository, or &lt;a href="https://github.com/jordanleal12/express-mongo-error-handler?tab=readme-ov-file#warning-handled-error-types" rel="noopener noreferrer"&gt;'Handled Error Types'&lt;/a&gt; section in the package readme file for a file picture of every error handled by this middleware. As you can see, the middleware handles the full expected range of errors we would want to explicitly catch and format from our core MERN stack API libraries.&lt;/p&gt;

&lt;h3&gt;
  
  
  2. Gracefully handling errors from the most popular libraries used alongside this stack (jsonwebtoken, zod)
&lt;/h3&gt;

&lt;p&gt;In the above code block, I provided an example of &lt;code&gt;if&lt;/code&gt; blocks for express error types. Here is an example of an &lt;code&gt;if&lt;/code&gt; block to handle a jsonwebtoken error:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;name&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;TokenExpiredError&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;status&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;401&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;json&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
    &lt;span class="na"&gt;success&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;message&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Expired token&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;errors&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Your session has expired. Please log in again to refresh.&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
  &lt;span class="p"&gt;});&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This is just one example to demonstrate specific handling of core third party library errors within this middleware, refer to &lt;a href="https://github.com/jordanleal12/express-mongo-error-handler?tab=readme-ov-file#warning-handled-error-types" rel="noopener noreferrer"&gt;the documentation&lt;/a&gt; to see the remaining.&lt;br&gt;
As seen from just three examples, each &lt;code&gt;if&lt;/code&gt; block has had to deal with a different error shape, requiring different checks for &lt;code&gt;err instanceOf&lt;/code&gt;, &lt;code&gt;err.status&lt;/code&gt;, &lt;code&gt;err.type&lt;/code&gt; and &lt;code&gt;err.name&lt;/code&gt; depending on the error being handled, demonstrating the importance of having specific error handling capabilities to deal with the multitude of error types returned from different libraries.&lt;/p&gt;
&lt;h3&gt;
  
  
  3. Formatting of errors into consistent responses for the client regardless of error type
&lt;/h3&gt;

&lt;p&gt;Regardless of the shape of the error being caught, the middleware will always return a consistent response structure, allowing for simple and easy integration with a front end.&lt;br&gt;
Lets use the above example to break down the response structure:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="c1"&gt;// Appropriate http error status code always included&lt;/span&gt;
  &lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;status&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;401&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;json&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
    &lt;span class="na"&gt;success&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="c1"&gt;// Success always set to false for errors, allowing for easy client boolean check&lt;/span&gt;
    &lt;span class="na"&gt;message&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Expired token&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="c1"&gt;// Message contains simple summary of error&lt;/span&gt;
    &lt;span class="c1"&gt;// Errors array contains one or more verbose error messages from original error object&lt;/span&gt;
    &lt;span class="na"&gt;errors&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Your session has expired. Please log in again to refresh.&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
  &lt;span class="p"&gt;});&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Certain mongoose errors will return an array of objects in their &lt;code&gt;errors&lt;/code&gt; array. This allows easy mapping for the client of the specific field that triggered the error (e.g. an email field causing a validation error):&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;success&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;message&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Duplicate key violation&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;errors&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;field&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;email&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;message&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Record with field 'email' already exists&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;field&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;username&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;message&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Record with field 'username' already exists&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="p"&gt;]&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  4. Integration with third party logging tools
&lt;/h3&gt;

&lt;p&gt;By default, when logging is enabled the middleware will log an object to &lt;code&gt;console.error&lt;/code&gt; that includes the error name, code, message, and optional stack trace. For those wishing to use external logging libraries, integration is extremely simple.&lt;br&gt;
Here is an example of configuring the middleware using the &lt;code&gt;winston&lt;/code&gt; logging package:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;winston&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;winston&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;logger&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;winston&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;createLogger&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
  &lt;span class="cm"&gt;/* config */&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;

&lt;span class="c1"&gt;// Assign your logger to the `logger` argument&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;errorHandler&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;createErrorHandler&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="na"&gt;logger&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;logger&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;error&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;bind&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;logger&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;});&lt;/span&gt;
&lt;span class="nx"&gt;app&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;use&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;errorHandler&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;It's that easy! Refer to the &lt;a href="https://github.com/jordanleal12/express-mongo-error-handler?tab=readme-ov-file#gear-configuration-options" rel="noopener noreferrer"&gt;Configuration Options&lt;/a&gt; section of the documentation to see additional examples for &lt;code&gt;pino&lt;/code&gt; and &lt;code&gt;bunyan&lt;/code&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  5. Configuration options to decide whether to include stack traces in development for debugging, defaulted to not include for safety
&lt;/h3&gt;

&lt;p&gt;Let's have a look at the &lt;code&gt;createErrorHandler&lt;/code&gt; configuration options:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// Check for development or test environment (false without environment variables for safety)&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;notProduction&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;process&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;env&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;NODE_ENV&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;development&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="nx"&gt;process&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;env&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;NODE_ENV&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;test&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="c1"&gt;// Destructured createErrorHandler configuration options with defaults&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;logErrors&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;notProduction&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="nx"&gt;exposeStack&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="nx"&gt;logger&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;error&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="nx"&gt;customHandlers&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[],&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;options&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;As seen in the above, &lt;code&gt;logErrors&lt;/code&gt; is set to &lt;code&gt;notProduction&lt;/code&gt;, meaning by default this middleware will only log errors when &lt;code&gt;NODE_ENV&lt;/code&gt; environment variable exists and is set to "development" or "test".&lt;br&gt;
More importantly, &lt;code&gt;exposeStack&lt;/code&gt; is set to false by default, an option seen missing in most other error handling middleware packages previously discussed. Of course each of these options can be configured as desired when initializing the middleware. For example, if a user wished to always log errors, and exclude stack traces only in production:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;errorHandler&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;createErrorHandler&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
  &lt;span class="na"&gt;logErrors&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;exposeStack&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;process&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;env&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;NODE_ENV&lt;/span&gt; &lt;span class="o"&gt;!==&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;production&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="c1"&gt;// Equates to false in production only&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;
&lt;span class="nx"&gt;app&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;use&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;errorHandler&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  6. Ability to gracefully catch and respond to custom application errors
&lt;/h3&gt;

&lt;p&gt;Many users will want to create their own custom error classes, or throw specific custom errors in certain routes. Since normal error objects don't have a statusCode property, so long as any custom application error is thrown with a statusCode, it can be caught with the following:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;statusCode&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;status&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;statusCode&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;json&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
    &lt;span class="na"&gt;success&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;message&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;message&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;errors&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;errors&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;message&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
  &lt;span class="p"&gt;});&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Here's an example of a custom error class being created and used throw an error in a route:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// Creation of custom error class. Must contain statusCode property to be handled appropriately&lt;/span&gt;
&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;CustomError&lt;/span&gt; &lt;span class="kd"&gt;extends&lt;/span&gt; &lt;span class="nc"&gt;Error&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nf"&gt;constructor&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;message&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;statusCode&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;errors&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[])&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;super&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;message&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;statusCode&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;statusCode&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;errors&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;errors&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;length&lt;/span&gt; &lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="nx"&gt;errors&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;message&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="c1"&gt;// Example usage in routes&lt;/span&gt;
&lt;span class="nx"&gt;app&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;/api/users/:id&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;async &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;req&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;next&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;try&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;user&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;User&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;findById&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;req&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;params&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="nx"&gt;user&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="k"&gt;throw&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;CustomError&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;User not found&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;404&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;json&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;user&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;catch &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;error&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nf"&gt;next&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;error&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Since it contains a statusCode, this error will be handled by our middleware.&lt;/p&gt;

&lt;h3&gt;
  
  
  7. Ability for user to pass additional custom error handlers to handle other library errors
&lt;/h3&gt;

&lt;p&gt;Our middleware package responds to the core MERN backend errors, and some of the most popular libraries, but how about handling of other third party library errors that aren't accounted for? For example, a user with the &lt;code&gt;stripe&lt;/code&gt; or &lt;code&gt;multer&lt;/code&gt; package installed will need to account for the unique type of errors thrown by those libraries if they wish to return a more meaningful response than the generic 500 error.&lt;/p&gt;

&lt;p&gt;Thankfully our middleware makes this incredibly easy by accepting an array of custom error handlers as a configuration option. Take a look at the following code:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// Array of custom error handler functions for adding additional package compatibility&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;customHandlers&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
  &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;req&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="c1"&gt;// Example 'stripe' package error handler&lt;/span&gt;
    &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;type&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;StripeCardError&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;status&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;402&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;json&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
        &lt;span class="na"&gt;success&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="na"&gt;message&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Payment failed&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="na"&gt;errors&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;message&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
      &lt;span class="p"&gt;});&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="p"&gt;},&lt;/span&gt;
  &lt;span class="c1"&gt;// Each 'if' block can be a separate function or wrapped in a single function as desired&lt;/span&gt;
  &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;req&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="c1"&gt;// Example 'multer' package error handler&lt;/span&gt;
    &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;name&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;MulterError&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;status&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;400&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;json&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
        &lt;span class="na"&gt;success&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="na"&gt;message&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;File upload error&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="na"&gt;errors&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;message&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
      &lt;span class="p"&gt;});&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="p"&gt;},&lt;/span&gt;
  &lt;span class="cm"&gt;/* Additional error handlers as required */&lt;/span&gt;
&lt;span class="p"&gt;];&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;errorHandler&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;createErrorHandler&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="nx"&gt;customHandlers&lt;/span&gt; &lt;span class="p"&gt;});&lt;/span&gt; &lt;span class="c1"&gt;// Pass handlers to config&lt;/span&gt;
&lt;span class="nx"&gt;app&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;use&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;errorHandler&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In this example, the user has created the &lt;code&gt;customHandlers&lt;/code&gt; array, containing an error handling function for a stripe error and multer error respectively. This array is then passed to &lt;code&gt;createErrorHandler&lt;/code&gt; as the shorthand &lt;code&gt;customHandlers&lt;/code&gt; parameter (we can use shorthand as the name of the array matches the name of the config parameter). Custom error handlers are checked against the error object before the default error handlers, using the following code:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// Run error through any custom error handlers first&lt;/span&gt;
&lt;span class="k"&gt;for &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;handler&lt;/span&gt; &lt;span class="k"&gt;of&lt;/span&gt; &lt;span class="nx"&gt;customHandlers&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;result&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;handler&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;req&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;result&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;result&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="c1"&gt;// Will return response and exit if custom handler catches error&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The &lt;code&gt;customHandlers&lt;/code&gt; functionality will work regardless of if it's passed an array of separate functions like the above example, an array with a single function containing multiple &lt;code&gt;if&lt;/code&gt; blocks, or a combination of either. Since the errors are handled within the &lt;code&gt;createErrorHandler&lt;/code&gt; middleware function, the same configuration options are applied to errors handled by your &lt;code&gt;customHandlers&lt;/code&gt; array.&lt;/p&gt;

&lt;h3&gt;
  
  
  8. Catch-all error handler to ensure any unexpected errors are handled gracefully
&lt;/h3&gt;

&lt;p&gt;A must have for any error handling middleware, the following code catches any unhandled error to ensure we never crash the application with uncaught errors:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;status&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;500&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;json&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
  &lt;span class="na"&gt;success&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;message&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Unexpected error.&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;errors&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;An unexpected error occurred. Please try again later.&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This is defined last within the function, and will only trigger if none of the preceding &lt;code&gt;if&lt;/code&gt; blocks are triggered.&lt;/p&gt;

&lt;h3&gt;
  
  
  9. JSDoc tooltips for ease of use
&lt;/h3&gt;

&lt;p&gt;JSDoc tooltips where added to the package to ensure the user could quickly identify key characteristics of the middleware function without having to refer to the documentation every time. Here is what the tooltips look like in the file:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="cm"&gt;/**
 * express-mongo-error-handler
 * ==============================
 * Create a configurable error-handling middleware for use with Express.js, designed for the
 * backend of MERN applications.
 *
 * Why use this middleware:
 * - Provides default error handling for common express API setups (Express, Mongoose, JWT, Zod)
 * - Prevents leaking of stack traces and sensitive data to clients in production
 * - Consistent response format structure ensures easy front end integration
 * - Works with custom errors, http-errors package, Zod, etc.
 * - Configurable logging and stack trace exposure with environment based defaults
 * - Uses console.error by default but allows custom logger function
 * - Accepts array of custom error handlers for additional flexibility
 *
 * Installation: npm install express-mongo-error-handler
 *
 * @param {Object} options - Configuration options object
 * @param {boolean} [options.logErrors=notProduction] - Option to log error details to logger
 * @param {boolean} [options.exposeStack=false] - Option to expose stack traces in error logging
 * @param {Function} [options.logger=console.error] - Accepts custom logger function for error logging
 * @param {Array&amp;lt;Function&amp;gt;} [options.customHandlers=[]] - Array of custom error handler functions
 * @returns {Function} Express error-handling middleware (err, req, res, next)
 */&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And here is how that displays to a user when hovering on the function:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F7wi0j6mrbam5t2n2vcnp.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F7wi0j6mrbam5t2n2vcnp.png" alt="Image of JSDoc on hover tooltip while hovering 'createErrorHandler' function" width="800" height="266"&gt;&lt;/a&gt;&lt;br&gt;
&lt;em&gt;Scrollable JSDoc tooltip appears when hovering 'createErrorHandler' function&lt;/em&gt;&lt;/p&gt;


&lt;h2&gt;
  
  
  Project Planning
&lt;/h2&gt;

&lt;p&gt;As most experienced developers will tell you, planning for a project is key to it's success. This is particularly true when tackling something new, which for me was creating and publishing an NPM project.&lt;br&gt;
Let's walk through the planning steps I undertook to ensure this project would be successful, and the time estimates for each step.&lt;/p&gt;
&lt;h3&gt;
  
  
  1. Identify Project Requirements
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;&lt;em&gt;Estimate - 2.5hrs&lt;/em&gt;&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;We've already covered in detail the project requirements in the 'The Problem' section, however it is important to note that this article is referring to version 1.2.0 (the latest version as of writing this blog). This version is the fourth release of my package, and has additional features added compared to the initial release. The reason for this, is that project planning should ideally identify two sets of requirements - one set for the ideal 'full-feature' version, and another for the 'MVP' (Minimum Viable Product) version.&lt;/p&gt;

&lt;p&gt;There is no definitive 'correct' way to plan and deploy an application, but for my project I chose to use 'Iterative Development', i.e create and deploy my MVP product and then add additional desired features afterwards. Planning and identifying my MVP requirements was centred around the following:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;What are the ideal features of the project?&lt;/strong&gt;
Since the current version of my package has integration of all of the initial ideal features, refer to the &lt;a href="https://github.com/jordanleal12/express-mongo-error-handler?tab=readme-ov-file#jigsaw-features" rel="noopener noreferrer"&gt;features section&lt;/a&gt; of the readme to view the initially planned ideal features.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;What is the core functionality of the project?:&lt;/strong&gt;
The core functionality for this package is to handle Express, Mongoose/MongoDb, zod, jsonwebtoken and unexpected errors in a centralized middleware, with stack traces not included in logging by default, with the option to include stack traces in logs for debugging.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;What is required for the project to function?:&lt;/strong&gt;
Rather than listing each feature kept for the MVP, let's list the features that were deemed unnecessary for our MVP version -

&lt;ul&gt;
&lt;li&gt;CommonJS, MJS and TypeScript support. Creating a bundled version of the package with support for all three required a decent amount of extra configuration and research, so initially the package was rolled out with MJS support only.&lt;/li&gt;
&lt;li&gt;Integration with custom error handlers. Since this was technically doable for the user without the addition of a specific feature to make it simple, this was removed from MVP requirements&lt;/li&gt;
&lt;li&gt;JSdoc tooltips. Not required for user functionality but a great addition to improve user experience, this was left out of MVP requirements.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;
  
  
  2. Research Existing Resources
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;&lt;em&gt;Estimate - 3hrs&lt;/em&gt;&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Now that I had identified the key features required, before potentially wasting further time on planning this project the most vital next step was to research if any packages had already addressed my needs. There are few things more disappointing to a developer than investing time and energy on developing a feature only to discover there was a package that already did it for you. After identifying which keywords corresponded to the core package functionality, I searched through the NPM repository and other online resources to find the packages that most closely aligned with my core desired features, listed in the 'How Has This Problem Already Been Addressed?' section.&lt;/p&gt;
&lt;h3&gt;
  
  
  3. Choose Language/Tools/Frameworks etc
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;&lt;em&gt;Estimate - 2hrs&lt;/em&gt;&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;This will be expanded in greater detail in the 'Skills, Technologies, Languages &amp;amp; Frameworks' section, but to summarize:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Vanilla Javascript for the MVP build with TypeScript files added in a successive feature&lt;/li&gt;
&lt;li&gt;Node.js for runtime environment, middleware execution and NPM ecosystem&lt;/li&gt;
&lt;li&gt;Express for the error middleware pattern (error, request, response, next)&lt;/li&gt;
&lt;li&gt;MongoDB/Mongoose, jsonwebtoken, and zod, not used directly but researched to be able to handle their error objects&lt;/li&gt;
&lt;li&gt;Git &amp;amp; GitHub for version control&lt;/li&gt;
&lt;li&gt;NPM for package management and uploading/updating of package upon completion&lt;/li&gt;
&lt;li&gt;Tsup for bundling later version of package&lt;/li&gt;
&lt;li&gt;Jest for testing&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;
  
  
  4. Plan Project Structure
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;&lt;em&gt;Estimate - 30m&lt;/em&gt;&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Planning the project structure was broken into two phases, the MVP structure and the structure for successive iterations. After identifying the core features required for the MVP version and the languages/frameworks etc. listed above, the next step was to identify what specific files where required and organize them as desired:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;├── express-mongo-error-handler (MVP Version)
│   ├── .git  # Folder containing git version control files
│   │   └── ...
│   ├── .gitignore  # Define files to be ignored by git
│   ├── .npmignore  # Define files to be ignored when uploading to NPM
│   ├── CONTRIBUTING.md  # Guidelines on open source contribution
│   ├── LICENSE  # Open source MIT licence
│   ├── README.md  # Main project documentation
│   ├── SECURITY.md  # Security policy
│   ├── index.js  # Entry point of application with core package functionality
│   ├── node_modules  # Folder containing NPM packages
|   |  └── ...
│   ├── package-lock.json  # Detailed record of dependency tree
│   ├── package.json  # Metadata and configuration settings for project
│   └──test  # Test folder
│       └── createErrorHandler.test.js  # Test file for core package method
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;After defining the required structure for the MVP version, the structure for the full feature version was planned:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;├── express-mongo-error-handler (Current Version)
|   ├── &amp;lt;previously shown folders/files&amp;gt;
│   ├── dist  # Folder containing compiled versions of project assets
│   │   ├── index.cjs  # CommonJS compatible compiled main application file
│   │   └── index.js  # Module (MJS) compatible compiled main application file
│   ├── index.d.cts  # TypeScript declaration file for CommonJS
│   ├── index.d.ts  # TypeScript declaration file for ESM
│   └── tsup.config.js  # Configuration file for tsup bundler
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  5. Plan Tests
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;&lt;em&gt;Estimate - 1.5hrs&lt;/em&gt;&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;In line with principles of TDD, planning and writing tests before writing code gives a clear picture of what specific functionality the code needs to provide to pass the tests. For the MVP version of the project, the following tests where planned:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Configuration Tests:&lt;/strong&gt; Unit tests to assert that the configuration options object to be passed to the middleware function changes its functionality as desired&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Express Error Handling Tests:&lt;/strong&gt; Unit tests to assert express errors are caught and responded to as desired&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Mongoose/MongoDB Error Handling Tests:&lt;/strong&gt; Unit tests to assert Mongoose/MongoDB errors are caught and responded to as desired&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Jsonwebtoken Error Handling Tests:&lt;/strong&gt; Unit tests to assert jsonwebtoken errors are caught and responded to as desired&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Zod Error Handling Tests:&lt;/strong&gt; Unit tests to assert zod errors are caught and responded to as desired&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Custom Application Error Handling Tests:&lt;/strong&gt; Unit tests to assert custom application errors are caught and responded to as desired&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Catch-All Error Handling Tests:&lt;/strong&gt; Unit tests to assert unexpected/unhandled errors are caught and responded to as desired&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;After completion of the MVP version, unit tests to assert custom error handlers array configuration caught and handled errors correctly was planned and added.&lt;/p&gt;




&lt;h2&gt;
  
  
  Skills, Technologies, Languages &amp;amp; Frameworks
&lt;/h2&gt;

&lt;p&gt;We mentioned in the 'Project Planning' section which tools we decided to use in the project, but what went into that decision making process? Lets review each tool used, why it was required, the skills needed to use it, what the alternatives where (if any) and why it was chosen:&lt;/p&gt;

&lt;h3&gt;
  
  
  1. JavaScript
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Why It Was Required:&lt;/strong&gt; The package was built to target a specific issue MERN issue, which is built on JavaScript&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Skills Needed:&lt;/strong&gt; Basic JS competency as well as understanding asynchronous programming, object destructuring, stack trace debugging &amp;amp; error propagation&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Alternative Options:&lt;/strong&gt; TypeScript or any language that compiles to JavaScript&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Why This Was Chosen:&lt;/strong&gt; JS is the most popular programming language, and although TS is growing in popularity and offers many distinct advantages, as a junior developer I am not yet at a stage of competency to use TS for this project.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  2. Node.js
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Why It Was Required:&lt;/strong&gt; Core ecosystem used by MERN which this package targets, enables usage of NPM ecosystem&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Skills Needed:&lt;/strong&gt; asynchronous programming, object destructuring, stack trace debugging &amp;amp; error propagation, NPM package management and creation&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Alternative Options:&lt;/strong&gt; None if targetting MERN users (the 'N' is for Node)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Why This Was Chosen:&lt;/strong&gt; No alternatives&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  3. Express
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Why It Was Required:&lt;/strong&gt; Core framework used by MERN which this package targets. Not used as a package but as a target of the project&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Skills Needed:&lt;/strong&gt; Middleware usage, request and response structure, industry preferences for responses, express error structure&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Alternative Options:&lt;/strong&gt; None if targetting MERN users (the 'E' is for Express)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Why This Was Chosen:&lt;/strong&gt; No alternatives&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  4. MongoDB/Mongoose
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Why It Was Required:&lt;/strong&gt; Core database and db manager used by MERN which this package targets. Not used as a package but as a target of the project&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Skills Needed:&lt;/strong&gt; Mongo model and schema usage, MongoDB and Mongoose error structure, async db queries&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Alternative Options:&lt;/strong&gt; None for MongoDb if targetting MERN users (the 'M' is for MongoDB), Camo, Prisma or direct MongoDB interaction as an alternative to Mongoose&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Why This Was Chosen:&lt;/strong&gt; No alternative for MongoDB, Mongoose is by far the most popular ODM in MERN packages making it the most suitable to target.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  5. Jsonwebtoken
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Why It Was Required:&lt;/strong&gt; To meet one of the key purposes of this package, which was to target core MERN libraries and the most used third party packages. Not used as a package but as a target of the project&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Skills Needed:&lt;/strong&gt; Understanding JWT authentication usage, jsonwebtoken error structure&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Alternative Options:&lt;/strong&gt; jose, passport, paseto&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Why This Was Chosen:&lt;/strong&gt; This package remains the most popular JWT authentication package, making it the most suitable to target.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  6. Zod
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Why It Was Required:&lt;/strong&gt; To meet one of the key purposes of this package, which was to target core MERN libraries and the most used third party packages. Not used as a package but as a target of the project&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Skills Needed:&lt;/strong&gt; Understanding zod schema usage and validation, zod error structure&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Alternative Options:&lt;/strong&gt; ajv, joi, yup&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Why This Was Chosen:&lt;/strong&gt; Although ajv is currently more popular than zod, adoption of zod has seen a dramatic explosion of growth, leading me to choose this as a more forward thinking package to target. Additionally, ajv has a much steeper learning curve than zod and targets more advanced application users. This project targets more junior/beginner developers, who are more likely to be using zod by comparison.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  7. Jest
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Why It Was Required:&lt;/strong&gt; Unit testing the application&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Skills Needed:&lt;/strong&gt; Writing test suites, mocking API objects, async testing&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Alternative Options:&lt;/strong&gt; Mocha, Postman, AVA&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Why This Was Chosen:&lt;/strong&gt; As only relatively basic unit tests where required for this project, and I was already familiar and comfortable with this package, there was no comparative advantage to having to learn a new testing package.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  8. NPM
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Why It Was Required:&lt;/strong&gt; Hosting platform for this package, dependency manager for Node.js&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Skills Needed:&lt;/strong&gt; Dependency installations commands, configuring package.json for publishing, package versioning, package publishing commands&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Alternative Options:&lt;/strong&gt; yarn, pnpm&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Why This Was Chosen:&lt;/strong&gt; Most popular package manager for backends, familiar usage&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  9. Tsup
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Why It Was Required:&lt;/strong&gt; To build/bundle the package for distribution on NPM, allowing for compatibility with CJS and ESM usage&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Skills Needed:&lt;/strong&gt; Setting up tsup configuration files, understanding outputs required for different compatibility options&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Alternative Options:&lt;/strong&gt; rollup, tsdown, esbuild&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Why This Was Chosen:&lt;/strong&gt; tsup is a wrapper of esbuild with easy config and good default config options, ideal for a small package like this. Tsdown was a suitable alternative but is yet to reach stable release.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  10. TypeScript
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Why It Was Required:&lt;/strong&gt; Adding TS support for type checking and intelliSense, and to enable JSdoc function comments for both import styles&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Skills Needed:&lt;/strong&gt; tsconfig usage with TS, JSdoc syntax, basic TS requirements for type checking&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Alternative Options:&lt;/strong&gt; Using tsup to automatically generate TS files from index.js&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Why This Was Chosen:&lt;/strong&gt; Using tsup automatic configuration was not getting the JSdoc function comments to display correctly when using CJS imports&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  11. Git/Github
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Why It Was Required:&lt;/strong&gt; Version control for hosting and managing code, centralized platform to allow open source contribution&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Skills Needed:&lt;/strong&gt; Basic git usage (branching, commits, etc.), conventional commit comments, requirements for open source documentation, tags for NPM packaging&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Alternative Options:&lt;/strong&gt; SVN, GitLab, BitBucket&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Why This Was Chosen:&lt;/strong&gt; The most popular combination of version control and management, and the one with which I am most familiar&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  How This Project Improved My Skills
&lt;/h2&gt;

&lt;p&gt;This project was a great learning experience for me, one of many 'firsts'. It was my first NPM package, my first time working with TypeScript, first time compiling a library and my first time creating a solo open source project. Let's have a look at the different skills I upgraded while working on this project:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;&lt;strong&gt;Skill&lt;/strong&gt;&lt;/th&gt;
&lt;th&gt;&lt;strong&gt;Knowledge Before&lt;/strong&gt;&lt;/th&gt;
&lt;th&gt;&lt;strong&gt;Knowledge After&lt;/strong&gt;&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Creating NPM package&lt;/td&gt;
&lt;td&gt;❌ None&lt;/td&gt;
&lt;td&gt;✅ Competent&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Package Versioning&lt;/td&gt;
&lt;td&gt;❌ None&lt;/td&gt;
&lt;td&gt;✅ Competent&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Compiling a Package&lt;/td&gt;
&lt;td&gt;❌ None&lt;/td&gt;
&lt;td&gt;✅ Competent&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Configuring &lt;code&gt;package.json&lt;/code&gt;
&lt;/td&gt;
&lt;td&gt;✅ Competent&lt;/td&gt;
&lt;td&gt;💎 Advanced&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;TypeScript Declaration Files&lt;/td&gt;
&lt;td&gt;❌ None&lt;/td&gt;
&lt;td&gt;✅ Competent&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;JSDoc Implementation&lt;/td&gt;
&lt;td&gt;🟡 Some&lt;/td&gt;
&lt;td&gt;✅ Competent&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Open Source Setup&lt;/td&gt;
&lt;td&gt;🟡 Some&lt;/td&gt;
&lt;td&gt;✅ Competent&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;MERN Error Handling&lt;/td&gt;
&lt;td&gt;✅ Competent&lt;/td&gt;
&lt;td&gt;💎 Advanced&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Middleware Usage&lt;/td&gt;
&lt;td&gt;✅ Competent&lt;/td&gt;
&lt;td&gt;💎 Advanced&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;API Security&lt;/td&gt;
&lt;td&gt;✅ Competent&lt;/td&gt;
&lt;td&gt;💎 Advanced&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;After completing this package, I am now confident in my ability to do the following:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Create, publish and update an NPM package, with semantic versioning&lt;/li&gt;
&lt;li&gt;Generate tarballs and test packages locally&lt;/li&gt;
&lt;li&gt;Configure &lt;code&gt;package.json&lt;/code&gt; correctly for a package, including description, exports, files, keywords etc.&lt;/li&gt;
&lt;li&gt;Write JSDoc code function comments, detailing arguments, return values and options&lt;/li&gt;
&lt;li&gt;Create TypeScript declaration files to give TS users type definitions and improve compatibility of JSDoc comments across import styles&lt;/li&gt;
&lt;li&gt;Compile a package using &lt;code&gt;tsup&lt;/code&gt;, setting up configuration options and providing compatibility for ESM ,CJS and TS usage&lt;/li&gt;
&lt;li&gt;Create open source projects with robust documentation&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  What Could I Do Differently In The Future?
&lt;/h2&gt;

&lt;p&gt;Although I'm pleased with my project, there are of course areas of competency identified during the course of creating this package that I would wish to improve further:&lt;/p&gt;

&lt;h3&gt;
  
  
  Improve Open Source Documentation
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Priority:&lt;/strong&gt; High&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Why:&lt;/strong&gt; The repository is currently missing an issue's template, a code of conduct, and a formal pull request template (although an example is provided within &lt;code&gt;CONTRIBUTING.md&lt;/code&gt;). These files will provide additional guidance and structure to any open source contributors wishing to collaborate on the project.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Why it wasn't implemented:&lt;/strong&gt; As my first lightweight package, my priority was to bring the open source documentation to a level that provided enough guidance for collaborators, while allowing myself time to research and implement additional open source documentation at a later time&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Convert Package To Typescript
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Priority:&lt;/strong&gt; Medium&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Why:&lt;/strong&gt; Since this project uses vanilla JS as its logic file and separate TS files to provide type definitions, complexity is added to the updating process, increasing the risk of forgetting to update one when updating the other. Additionally, this will improve ease of configuration using the &lt;code&gt;tsup&lt;/code&gt; bundler, and reduce complexity requirements for testing.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Why it wasn't implemented:&lt;/strong&gt; This project was my first time using TS, and I was not comfortable using it to write my packages logic but rather only to add type definitions. After learning TS usage in the future this can be implemented.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Setup CI/CD on GitHub
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Priority:&lt;/strong&gt; Medium&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Why:&lt;/strong&gt; This will greatly improve the experience of open source collaboration, allowing for automated environment creation and testing. When a collaborator commits or opens a pull request, GitHub Actions spins up a VM, installs project dependencies, and checks the new code passes existing tests. This standardizes staging and testing environments, reduces manual checking of collaborator contributions required, and ensures every addition passes tests.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Why it wasn't implemented:&lt;/strong&gt; Learning the processes and tools behind CI/CD is something I am doing concurrently to creating this package. Once I am more comfortable with the topic, I can look to implement CI/CD through GitHub Actions.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Create Integration Tests
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Priority:&lt;/strong&gt; High&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Why:&lt;/strong&gt; Current unit tests mock request and response objects only. Setting up a real Express app with an in memory DB for testing would dramatically improve the realism of the tests, closely mimicking real world usage.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Why it wasn't implemented:&lt;/strong&gt; My prioritization when building the application was automated unit testing with 100% coverage, while I manually tested integration. Although setting up automated integration would definitely improve application reliability, it wasn't required for the initial release of the package.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Customizable Response Structure
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Priority:&lt;/strong&gt; Low&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Why:&lt;/strong&gt; The current package is quite opinionated, meaning that users are essentially forced into using the response structure I deemed suitable unless they choose to rewrap their responses. An idealized version of this package would include a configuration to choose between response structure presets that reflect the most common API industry standards. Additionally, they should have the option to pass their own custom response structure to the handler that overwrites defaults.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Why it wasn't implemented:&lt;/strong&gt; As you can imagine, this approach would add significant complexity to the package, and stray slightly from the core values of being a lightweight and extremely easy to implement package that is beginner friendly. After implementing the other proposed changes to allow for a more consistent CI/CD environment, this is something I would still be interested to explore and implement.&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;Modern API creation is an ever increasingly relevant field for developers. Throughout this text we've explored:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;A common setup/security issue facing MERN stack API's&lt;/li&gt;
&lt;li&gt;The ethical and technical issues relevant to the problem&lt;/li&gt;
&lt;li&gt;How current industry trends relate to the problem&lt;/li&gt;
&lt;li&gt;How other existing resources have attempted to solve it&lt;/li&gt;
&lt;li&gt;The custom package I created as my own solution&lt;/li&gt;
&lt;li&gt;How I planned the project&lt;/li&gt;
&lt;li&gt;The skills and technologies required for the project and how I chose them&lt;/li&gt;
&lt;li&gt;How this project improved my skills as a developer&lt;/li&gt;
&lt;li&gt;Things that could be done differently in the future&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The result of this has been a drastic improvement in my own ability to understand and respond to errors within a MERN API safely, and in line with industry security expectations. I hope that you as the reader have had a similar experience! Remember, this is an open source project, so if you have desired improvements of your own, please feel free to contribute to &lt;a href="https://github.com/jordanleal12/express-mongo-error-handler" rel="noopener noreferrer"&gt;my GitHub repository&lt;/a&gt;. Thank you for exploring this topic with me, and hopefully this package and my exploration of this topic have been valuable to you!&lt;/p&gt;

&lt;h2&gt;
  
  
  References
&lt;/h2&gt;




&lt;ol&gt;

&lt;li id="fn1"&gt;
&lt;p&gt;&lt;a href="https://medium.com/@ujjawalr/stop-printing-stack-traces-in-prod-do-this-instead-028408af72f4" rel="noopener noreferrer"&gt;Stop Printing Stack Traces in Prod - Medium&lt;/a&gt; ↩&lt;/p&gt;
&lt;/li&gt;

&lt;li id="fn2"&gt;
&lt;p&gt;&lt;a href="https://cheatsheetseries.owasp.org/cheatsheets/Logging_Cheat_Sheet.html" rel="noopener noreferrer"&gt;Logging Cheat Sheet - OWASP&lt;/a&gt; ↩&lt;/p&gt;
&lt;/li&gt;

&lt;li id="fn3"&gt;
&lt;p&gt;&lt;a href="https://www.hackerone.com/blog/logging-silent-security-guard-and-its-pitfalls" rel="noopener noreferrer"&gt;Logging: The Silent Security Guard and Its Pitfalls - HackerOne&lt;/a&gt; ↩&lt;/p&gt;
&lt;/li&gt;

&lt;li id="fn4"&gt;
&lt;p&gt;&lt;a href="https://www.acm.org/code-of-ethics" rel="noopener noreferrer"&gt;Code of Ethics - ACM&lt;/a&gt; ↩&lt;/p&gt;
&lt;/li&gt;

&lt;li id="fn5"&gt;
&lt;p&gt;&lt;a href="https://www.computer.org/education/code-of-ethics" rel="noopener noreferrer"&gt;Code of Ethics - IEEE-CM&lt;/a&gt; ↩&lt;/p&gt;
&lt;/li&gt;

&lt;li id="fn6"&gt;
&lt;p&gt;&lt;a href="https://content.salt.security/state-api-report.html" rel="noopener noreferrer"&gt;State of API Security Report 2025 - Salt&lt;/a&gt; ↩&lt;/p&gt;
&lt;/li&gt;

&lt;li id="fn7"&gt;
&lt;p&gt;&lt;a href="https://owasp.org/Top10/A05_2021-Security_Misconfiguration/" rel="noopener noreferrer"&gt;API Security Top Ten: #5 Security Misconfiguration - OWASP&lt;/a&gt; ↩&lt;/p&gt;
&lt;/li&gt;

&lt;li id="fn8"&gt;
&lt;p&gt;&lt;a href="https://survey.stackoverflow.co/2024/technology" rel="noopener noreferrer"&gt;2024 Developer Survey - Stack Overflow&lt;/a&gt; ↩&lt;/p&gt;
&lt;/li&gt;

&lt;li id="fn9"&gt;
&lt;p&gt;&lt;a href="https://survey.stackoverflow.co/2025/technology/" rel="noopener noreferrer"&gt;2025 Developer Survey - Stack Overflow&lt;/a&gt; ↩&lt;/p&gt;
&lt;/li&gt;

&lt;li id="fn10"&gt;
&lt;p&gt;&lt;a href="https://devecosystem-2025.jetbrains.com/tools-and-trends" rel="noopener noreferrer"&gt;2025 State of the Developer Ecosystem (Tools and Trends) - Jetbrain&lt;/a&gt; ↩&lt;/p&gt;
&lt;/li&gt;

&lt;li id="fn11"&gt;
&lt;p&gt;&lt;a href="https://www.sarojdangol012.com.np/blogs/why-mern-stack-dominates-2025" rel="noopener noreferrer"&gt;Why Mern Stack Dominates in 2025 - Saroj Dangol&lt;/a&gt; ↩&lt;/p&gt;
&lt;/li&gt;

&lt;li id="fn12"&gt;
&lt;p&gt;&lt;a href="https://www.npmjs.com/package/jsonwebtoken" rel="noopener noreferrer"&gt;jsonwebtoken - NPM&lt;/a&gt; ↩&lt;/p&gt;
&lt;/li&gt;

&lt;li id="fn13"&gt;
&lt;p&gt;&lt;a href="https://www.npmjs.com/package/zod" rel="noopener noreferrer"&gt;zod - NPM&lt;/a&gt; ↩&lt;/p&gt;
&lt;/li&gt;

&lt;li id="fn14"&gt;
&lt;p&gt;&lt;a href="https://www.npmjs.com/package/pino" rel="noopener noreferrer"&gt;pino - NPM&lt;/a&gt; ↩&lt;/p&gt;
&lt;/li&gt;

&lt;li id="fn15"&gt;
&lt;p&gt;&lt;a href="https://www.npmjs.com/package/errorhandler" rel="noopener noreferrer"&gt;errorhandler - NPM&lt;/a&gt; ↩&lt;/p&gt;
&lt;/li&gt;

&lt;li id="fn16"&gt;
&lt;p&gt;&lt;a href="https://www.npmjs.com/package/strong-error-handler" rel="noopener noreferrer"&gt;strong-error-handler - NPM&lt;/a&gt; ↩&lt;/p&gt;
&lt;/li&gt;

&lt;li id="fn17"&gt;
&lt;p&gt;&lt;a href="https://www.npmjs.com/package/express-error-toolkit" rel="noopener noreferrer"&gt;express-error-toolkit - NPM&lt;/a&gt; ↩&lt;/p&gt;
&lt;/li&gt;

&lt;li id="fn18"&gt;
&lt;p&gt;&lt;a href="https://www.npmjs.com/package/error-cure" rel="noopener noreferrer"&gt;error-cure - NPM&lt;/a&gt; ↩&lt;/p&gt;
&lt;/li&gt;

&lt;li id="fn19"&gt;
&lt;p&gt;&lt;a href="https://www.npmjs.com/package/express-mongo-error-handler/v/1.2.0" rel="noopener noreferrer"&gt;express-mongo-error-handler - NPM&lt;/a&gt; ↩&lt;/p&gt;
&lt;/li&gt;

&lt;li id="fn20"&gt;
&lt;p&gt;&lt;a href="https://github.com/jordanleal12/express-mongo-error-handler" rel="noopener noreferrer"&gt;express-mongo-error-handler - GitHub&lt;/a&gt; ↩&lt;/p&gt;
&lt;/li&gt;

&lt;/ol&gt;

</description>
      <category>mern</category>
      <category>middleware</category>
      <category>errors</category>
      <category>api</category>
    </item>
  </channel>
</rss>
