Functional Error Handling in Node.js With The Result Pattern
Learn how to improve your error handling in Node.js by using the Result Pattern. (5 Min)
Error handling is a crucial aspect for building robust applications.
In Node.js, error handling relies on try-catch blocks and exceptions.
While this is a common way in Node.js apps, it creates an unpredictable control flow and hidden failure points.
A few years ago, I discovered the Result Pattern approach for handling errors, and it completely changed the way I look at error handling in Node.js applications.
The Result Pattern approach makes errors explicit, type-safe, and part of your function signatures.
In today’s article, I’ll dig deeper into the error handling and how to use the Result Pattern to better manage it.
Problems With Using Exceptions For Flow Control
Most Node.js applications rely on exceptions for error handling.
You throw errors when something goes wrong, and catch them somewhere up the call stack.
This favors the so-called fail-fast principle because you terminate the method execution immediately once you throw an exception.
With this approach, you make the caller responsible for handling the exception.
The problem is that the client of the method must know which exceptions to handle, which is not obvious from the method’s signature.
This makes exceptions invisible and creates an opportunity for bugs related to improper error handling of these exceptions.
Code becomes unpredictable since you’re not sure if the method throws an exception or not.
Here is a simplified example of creating an order:
Use Exceptions For Exceptional Situations
A good rule of thumb is to use exceptions for unexpected errors and exceptional situations.
You basically have two types of errors:
Errors you know how to handle
Errors you don’t know how to handle
You can use exceptions for the errors you don’t know how to handle. And you should catch and handle them at the lowest level possible.
For the errors you know how to handle, you could use the Result Pattern and handle the errors in a more functional way.
Make these types of errors explicit since you already know about them.
This way is more explicit and clearly shows that the method can fail.
The drawback is that the caller of the method has to check whether the operation succeeded or failed.
Using The Result Pattern For Better Error-Handling
The Result Pattern makes errors explicit and type-safe.
Instead of throwing exceptions, methods return a Result object that contains the success data or error information.
You can think of the Result as a container that holds one of two things:
Success: Your data is inside.
Error (or Failure): Information about what went wrong.
The key change here is that errors become values, not exceptions.
You can handle them like any other data in your program.
Here is an example of what the Result object might look like:
Applying the Result Pattern
Now that we have the IResult interface and utility methods, we could refactor the above-mentioned example by switching from using exceptions to the Result Pattern.
You can notice a few things as improvements:
No more throwing exceptions.
The return type of the method is explicit - using the IResult return type.
It is clear what errors the method can return.
Another advantage of using the Result Pattern is that it simplifies the testing. It’s much easier to mock the Result object than to throw and handle exceptions.
As we said earlier, one drawback of the Result Pattern is its verbosity, as it might introduce more code compared to exceptions.
📌 TL;DR
Exceptions are for exceptional situations.
Use exceptions for errors you don’t know how to handle.
Use the Result Pattern for errors you know how to handle, making the error handling more explicit and obvious.
The Result Pattern allows you to handle errors more elegantly in a functional way, express the intent that the method could fail, and encapsulate the error inside.
So try out the Result Pattern and let me know how you found it.
I promise it will improve your code.
Hope this was helpful.
See you next time!
👋 Let’s connect
You can find me on LinkedIn, Twitter(X), Bluesky, or Threads.
I share daily practical tips to level up your skills and become a better engineer.
Thank you for being a great supporter, reader, and for your help in growing to 28K+ subscribers this week 🙏