<?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: vedant kale</title>
    <description>The latest articles on DEV Community by vedant kale (@vedant8177).</description>
    <link>https://dev.to/vedant8177</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.us-east-2.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F637572%2F14d86612-e98e-4b79-acd7-624ed2c939a9.png</url>
      <title>DEV Community: vedant kale</title>
      <link>https://dev.to/vedant8177</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/vedant8177"/>
    <language>en</language>
    <item>
      <title>Stop Writing try/catch in Every Controller</title>
      <dc:creator>vedant kale</dc:creator>
      <pubDate>Tue, 14 Jul 2026 12:28:30 +0000</pubDate>
      <link>https://dev.to/vedant8177/stop-writing-trycatch-in-every-controller-2bc3</link>
      <guid>https://dev.to/vedant8177/stop-writing-trycatch-in-every-controller-2bc3</guid>
      <description>&lt;p&gt;When I first started building APIs with Express.js, every async controller looked the same. I would write a &lt;code&gt;try&lt;/code&gt; block, perform some database operations, and then write a &lt;code&gt;catch&lt;/code&gt; block that called &lt;code&gt;next(error)&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;It worked, so I copied the same pattern into every controller. One controller became ten. Ten became fifty. Eventually, I realized that half of my controller code wasn't actually business logic, it was just repetitive error handling.&lt;/p&gt;

&lt;p&gt;That's when I discovered the &lt;strong&gt;Async Handler&lt;/strong&gt; pattern.&lt;/p&gt;




&lt;h1&gt;
  
  
  The Problem
&lt;/h1&gt;

&lt;p&gt;A typical Express controller often looks like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;getUser&lt;/span&gt; &lt;span class="o"&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;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;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="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;There's nothing wrong with this code.&lt;/p&gt;

&lt;p&gt;The problem is that &lt;strong&gt;every async controller ends up looking exactly the same.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Every file contains:&lt;/p&gt;

&lt;p&gt;try, catch and next(error)    &lt;/p&gt;

&lt;p&gt;over and over again. Besides being repetitive, it's also easy to forget. Miss one &lt;code&gt;try-catch&lt;/code&gt; block, and Express won't automatically catch errors thrown inside async functions.&lt;/p&gt;




&lt;h1&gt;
  
  
  What Is an Async Handler?
&lt;/h1&gt;

&lt;p&gt;An async handler is a small wrapper function that automatically catches errors from async controllers. Instead of every controller handling its own errors, the wrapper does it for you.&lt;/p&gt;




&lt;h1&gt;
  
  
  A Simple Analogy
&lt;/h1&gt;

&lt;p&gt;Imagine an office where every employee has to stop working whenever someone rings the front door. Besides doing their own job, they also have to greet every visitor. This quickly becomes repetitive and inefficient. Instead, the company hires a receptionist to handle every visitor. Now the employees can focus on their actual work while the receptionist takes care of the door. An async handler works the same way. Controllers focus on handling requests, while the async handler catches errors and passes them to Express's error handler.&lt;/p&gt;




&lt;h1&gt;
  
  
  Without an Async Handler
&lt;/h1&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;createUser&lt;/span&gt; &lt;span class="o"&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;create&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;body&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;status&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;201&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;It looks fine. Now imagine writing this in 40 different controllers. Most of the code ends up being identical.&lt;/p&gt;




&lt;h1&gt;
  
  
  With an Async Handler
&lt;/h1&gt;

&lt;p&gt;First, create the wrapper.&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;export&lt;/span&gt; &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;asyncHandler&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;fn&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;return &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="nb"&gt;Promise&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;resolve&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;fn&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="k"&gt;catch&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="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 the controller becomes:&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;export&lt;/span&gt; &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;createUser&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;asyncHandler&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="o"&gt;=&amp;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;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;create&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;body&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;status&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;201&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;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Notice how the controller only contains its actual responsibility. There is no &lt;code&gt;try-catch&lt;/code&gt;. If anything throws an error, the async handler catches it automatically and forwards it to Express.&lt;/p&gt;




&lt;h1&gt;
  
  
  How It Works
&lt;/h1&gt;

&lt;p&gt;The wrapper accepts your controller function.&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="nf"&gt;asyncHandler&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;fn&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;When Express executes it:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;Your controller runs.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;If everything succeeds, Express sends the response.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;If an error is thrown or a Promise rejects, &lt;code&gt;.catch(next)&lt;/code&gt; is called.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Express forwards the error to your global error middleware.&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Every controller gets consistent error handling without repeating code.&lt;/p&gt;




&lt;h1&gt;
  
  
  Common Mistakes to Avoid
&lt;/h1&gt;

&lt;h2&gt;
  
  
  1. Wrapping synchronous controllers
&lt;/h2&gt;

&lt;p&gt;Async handlers are designed for asynchronous functions. Normal synchronous routes usually don't need them.&lt;/p&gt;

&lt;h2&gt;
  
  
  2. Using try-catch inside every wrapped controller
&lt;/h2&gt;

&lt;p&gt;If you're already using an async handler, most controllers don't need their own &lt;code&gt;try-catch&lt;/code&gt; blocks. Only use one when you want to recover from a specific error.&lt;/p&gt;

&lt;h2&gt;
  
  
  3. Forgetting a global error middleware
&lt;/h2&gt;

&lt;p&gt;An async handler forwards errors; it doesn't send responses. Without a global error handler, those errors still won't be returned properly. So, create the global error middleware first.&lt;/p&gt;

&lt;h2&gt;
  
  
  4. Mixing business logic with error formatting
&lt;/h2&gt;

&lt;p&gt;Controllers should call services. The global error middleware should decide how errors are returned. Keep those responsibilities separate.&lt;/p&gt;




&lt;h1&gt;
  
  
  Conclusion
&lt;/h1&gt;

&lt;p&gt;An async handler doesn't make your application faster. It makes your code cleaner.&lt;/p&gt;

&lt;p&gt;Instead of writing the same &lt;code&gt;try-catch&lt;/code&gt; block in every controller, you write the wrapper once and reuse it everywhere. The result is smaller controllers, consistent error handling, and code that's much easier to maintain.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The lesson is simple:&lt;/strong&gt;&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Don't repeat error handling in every controller. Write it once, wrap your controllers, and let Express handle the rest.&lt;/p&gt;
&lt;/blockquote&gt;

</description>
      <category>programming</category>
      <category>javascript</category>
      <category>api</category>
      <category>learning</category>
    </item>
    <item>
      <title>Why Your Controllers Become 600+ Lines Long (And How a Service Layer Fixes It)</title>
      <dc:creator>vedant kale</dc:creator>
      <pubDate>Sun, 14 Jun 2026 19:47:20 +0000</pubDate>
      <link>https://dev.to/vedant8177/why-your-controllers-become-600-lines-long-and-how-a-service-layer-fixes-it-5bm0</link>
      <guid>https://dev.to/vedant8177/why-your-controllers-become-600-lines-long-and-how-a-service-layer-fixes-it-5bm0</guid>
      <description>&lt;p&gt;When I first started building APIs with Express.js, I made the same mistake many beginners make:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;"If it works, just put it in the controller."&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;So that's exactly what I did.&lt;/p&gt;

&lt;p&gt;Database queries? Controller.&lt;br&gt;
Validation? Controller.&lt;br&gt;
Business logic? Controller.&lt;br&gt;
Error handling? Controller. Everything lived in the same file.&lt;/p&gt;

&lt;p&gt;At first, this wasn't a problem. The project was small, the controllers were short, and finding bugs was easy. But as the application grew, so did the controllers. A controller that started with 20 lines slowly became 100 lines. Then 300. Then 600+ lines.&lt;/p&gt;

&lt;p&gt;At that point, reading the code became difficult. Finding bugs took longer, testing became harder, and making changes felt risky because every responsibility was mixed together in the same file. That's when I discovered the Service Layer pattern.&lt;/p&gt;
&lt;h2&gt;
  
  
  What Is a Service Layer?
&lt;/h2&gt;

&lt;p&gt;A service layer is responsible for handling your application's business logic.&lt;/p&gt;

&lt;p&gt;Think of it this way:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Routes decide which endpoint should be called.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Controllers handle HTTP requests and responses.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Services handle the actual business logic.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Business logic includes things such as:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Database queries&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Validation rules&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Permission checks&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;User-related operations&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Payment processing&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Business rules specific to your application&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Instead of putting all of this inside a controller, you move it into dedicated service files. This keeps your controllers small and focused while making your business logic easier to reuse, test, and maintain.&lt;/p&gt;
&lt;h2&gt;
  
  
  A Simple Analogy
&lt;/h2&gt;

&lt;p&gt;A controller is like a waiter in a restaurant. The waiter takes your order and brings your food to the table. However, the waiter doesn't cook the food. The kitchen does.&lt;/p&gt;

&lt;p&gt;In this analogy:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;The controller is the waiter.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;The service layer is the kitchen.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The controller receives the request, passes it to the service layer, and returns the result to the client. The actual work happens inside the service. &lt;/p&gt;
&lt;h2&gt;
  
  
  Without a Service Layer
&lt;/h2&gt;

&lt;p&gt;A typical controller often starts looking 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="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;getUser&lt;/span&gt; &lt;span class="o"&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="o"&gt;=&amp;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;id&lt;/span&gt; &lt;span class="o"&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="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;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;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;404&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;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;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="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;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;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;At first glance, this seems fine.&lt;/p&gt;

&lt;p&gt;The problem begins when more logic gets added:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Validation&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Authorization checks&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Database operations&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Error handling&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Business rules&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Eventually, the controller becomes responsible for everything.&lt;/p&gt;

&lt;h2&gt;
  
  
  With a Service Layer
&lt;/h2&gt;

&lt;p&gt;Controller:&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;export&lt;/span&gt; &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;getUser&lt;/span&gt; &lt;span class="o"&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="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="nf"&gt;getUserById&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;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;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="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;404&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;message&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;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;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Service:&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;export&lt;/span&gt; &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;getUserById&lt;/span&gt; &lt;span class="o"&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;id&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="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;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;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;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="p"&gt;}&lt;/span&gt;

  &lt;span class="k"&gt;return&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;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Notice the difference.&lt;/p&gt;

&lt;p&gt;The controller no longer knows how users are fetched. Its only responsibility is handling the request and returning a response. The service layer contains the business logic required to retrieve a user. This separation becomes increasingly valuable as your application grows.&lt;/p&gt;

&lt;h2&gt;
  
  
  Common Mistakes to Avoid
&lt;/h2&gt;

&lt;h3&gt;
  
  
  1. Putting all business logic inside controllers
&lt;/h3&gt;

&lt;p&gt;Controllers should not become the place where everything happens. Their primary responsibility is handling the request-response cycle.&lt;/p&gt;

&lt;h3&gt;
  
  
  2. Turning services into another controller
&lt;/h3&gt;

&lt;p&gt;Moving code to a service file is not enough. Services should contain business logic, not HTTP-specific logic such as &lt;code&gt;req&lt;/code&gt;, &lt;code&gt;res&lt;/code&gt;, or status codes.&lt;/p&gt;

&lt;h3&gt;
  
  
  3. Ignoring error handling
&lt;/h3&gt;

&lt;p&gt;Service functions can throw errors. Controllers should properly handle those errors and return appropriate responses.&lt;/p&gt;

&lt;h3&gt;
  
  
  4. Creating services too early for tiny projects
&lt;/h3&gt;

&lt;p&gt;Not every project needs a large architecture from day one. For small applications, simple controllers may be enough. As complexity grows, introducing services becomes more valuable.&lt;/p&gt;

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

&lt;p&gt;The biggest lesson is simple:&lt;br&gt;
&lt;strong&gt;Controllers handle requests and responses. Services handle business logic.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Keeping those responsibilities separate makes your code easier to read, test, maintain, and scale as your application grows. &lt;/p&gt;

&lt;p&gt;The goal isn't to follow architecture patterns for the sake of it. The goal is to prevent your controllers from becoming 600-line files that nobody enjoys maintaining.&lt;/p&gt;

</description>
      <category>webdev</category>
      <category>javascript</category>
      <category>programming</category>
      <category>architecture</category>
    </item>
    <item>
      <title>Fixing Circular Dependency Issues in My Node.js + Express API Project</title>
      <dc:creator>vedant kale</dc:creator>
      <pubDate>Thu, 23 Apr 2026 11:41:13 +0000</pubDate>
      <link>https://dev.to/vedant8177/fixing-circular-dependency-issues-in-my-nodejs-express-api-project-2nf3</link>
      <guid>https://dev.to/vedant8177/fixing-circular-dependency-issues-in-my-nodejs-express-api-project-2nf3</guid>
      <description>&lt;p&gt;While working on a Node.js + Express backend project, I ran into a frustrating issue caused by circular dependencies. It wasn’t immediately obvious, but it led to unpredictable runtime behavior and made debugging unnecessarily difficult.&lt;/p&gt;

&lt;p&gt;I was using &lt;strong&gt;barrel imports&lt;/strong&gt; (&lt;code&gt;index.ts&lt;/code&gt; files) inside the same module.&lt;br&gt;
At first, this felt clean and organized. But under the hood, it introduced hidden circular dependencies.&lt;/p&gt;

&lt;h3&gt;
  
  
  Example
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// fileA.ts&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;funcB&lt;/span&gt; &lt;span class="p"&gt;}&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;./index&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="c1"&gt;// fileB.ts&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;funcC&lt;/span&gt; &lt;span class="p"&gt;}&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;./index&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="c1"&gt;// fileC.ts&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;funcA&lt;/span&gt; &lt;span class="p"&gt;}&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;./index&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// index.ts (barrel file)&lt;/span&gt;
&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="o"&gt;*&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;./fileA&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="o"&gt;*&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;./fileB&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="o"&gt;*&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;./fileC&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The problem is, this creates a dependency loop:&lt;/p&gt;

&lt;p&gt;A → B → C → A&lt;/p&gt;

&lt;p&gt;Because of how Node.js module loading works, some modules are &lt;strong&gt;not fully initialized&lt;/strong&gt; when they are imported. This results in: &lt;code&gt;undefined&lt;/code&gt; values,   Hard-to-trace bugs&lt;/p&gt;

&lt;h2&gt;
  
  
  The fix
&lt;/h2&gt;

&lt;p&gt;To Fix this, I refactored the structure to remove circular dependencies completely.&lt;/p&gt;

&lt;h4&gt;
  
  
  1. Removed barrel imports inside the same module, Instead of importing from &lt;code&gt;./index&lt;/code&gt;, I switched to direct imports.
&lt;/h4&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// fileA.ts&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;funcB&lt;/span&gt; &lt;span class="p"&gt;}&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;./fileB&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h4&gt;
  
  
  2. Used relative imports for internal dependencies
&lt;/h4&gt;

&lt;h4&gt;
  
  
  3. Kept barrel files only for external usage, Barrel files are still useful. just not internally in the same module/folder.
&lt;/h4&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// modules/user/index.ts&lt;/span&gt;
&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="o"&gt;*&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;./user.controller&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="o"&gt;*&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;./user.service&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="o"&gt;*&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;./user.routes&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// outside the module&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;createUser&lt;/span&gt; &lt;span class="p"&gt;}&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;@/modules/user&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



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

&lt;p&gt;No more circular dependency issues, Cleaner and more predictable module structure, Easier debugging and maintenance&lt;/p&gt;

&lt;p&gt;Barrel imports are helpful for simplifying external imports, but using them &lt;strong&gt;inside the same module&lt;/strong&gt; can introduce hidden circular dependencies.&lt;/p&gt;

&lt;p&gt;Use &lt;strong&gt;direct relative imports internally&lt;/strong&gt; , Use &lt;strong&gt;barrel files only for external access&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;This small change can save hours of debugging and make your codebase significantly more stable.&lt;/p&gt;

</description>
      <category>webdev</category>
      <category>programming</category>
      <category>typescript</category>
      <category>api</category>
    </item>
  </channel>
</rss>
