Simplifying Error Handling in Your Node Application
Discover how to use middleware to handle errors in Express applications more efficiently.

In this article we will implement an error handling middleware in the context of an express application, allowing efficient management of errors in your application.
Problem: Repetition of processing conditions and poor error control management on the server
Result: Standardize error handling, allowing more efficient and consistent error management in your application.
Getting Started
Create a folder called helpers, inside it create a file api-error.ts

// helpers/api-error.ts
export class ApiError extends Error {
public readonly statusCode: number;
constructor(message: string, statusCode: number) {
super(message);
this.statusCode = statusCode;
}
}
export class BadRequestError extends ApiError {
constructor(message: string) {
super(message, 400);
}
}
export class NotFoundError extends ApiError {
constructor(message: string) {
super(message, 404);
}
}
export class UnauthorizedError extends ApiError {
constructor(message: string) {
super(message, 401);
}
}
ApiError
:
- This is a base class that extends JavaScript’s standard Error class.
- It has a statusCode property that stores the HTTP status code associated with the error.
- The constructor receives an error message and an HTTP status code, and calls the Error class constructor passing the error message.
- This class serves as a base for other custom error classes.
2. BadRequestError
, NotFoundError
, UnauthorizedError
:
- These are classes that extend the ApiError class.
- Each of them has a constructor that calls the ApiError class constructor with a specific error message and corresponding HTTP status code.
- For example, BadRequestError represents an invalid request error (status code 400), NotFoundError represents a resource not found error (status code 404), and UnauthorizedError represents an unauthorized error (status code 401).
These classes allow you to encapsulate different types of errors that can occur in an API and provide a consistent way to handle them. For example, when throwing a BadRequestError, you can provide a specific message indicating what went wrong with the request, and the class will ensure that the HTTP status code is set correctly when responding to the request.
This makes the code more readable and easier to maintain, and provides clear, meaningful responses to API clients.
Now let’s create the middleware
It is responsible for encapsulating the logic to determine the status code and error message, making the code more modular and easier to maintain.

import { NextFunction, Request, Response } from "express";
import { ApiError } from "../helpers/api-erros";
export const errorMiddleware = (
error: Error & Partial<ApiError>,
req: Request,
res: Response,
next: NextFunction
) => {
const statusCode = error.statusCode ?? 500;
const message = error.statusCode ? error.message : 'Internal Server Error';
return res.status(statusCode).json({ message });
};
The errorMiddleware middleware is a function that handles errors in an Express application. It receives four parameters: error, req, res and next.
- error.statusCode ?? 500;: Checks if the error has an associated status code. If so, use this code; otherwise, it uses the default error code 500 (Internal Server Error).
- error.statusCode ? error.message : ‘Internal Server Error’;: Defines the error message. If there is a message associated with the error, it is used; otherwise, a standard internal server error message is used.
- return res.status(statusCode).json({ message });: Returns a JSON response with the status code and error message.
Basically, the middleware checks to see if there is a status code and message associated with the error. If there are, it uses them in the response; otherwise, it uses a default status code and default error message. This helps ensure consistent responses across the application in case of errors.
Importing the middleware:
In your config or index.ts file at the root of your project express, add the middleware in the context of your application.

app.use(errorMiddleware)
Let’s use:
Here we have a use case where using the middleware within the context of error handling in the user controller.

export class UserController {
async create(req: Request, res: Response) {
try {
// your code
if (userExists) {
throw new BadRequestError('Email already exists');
}
if (!user && !verifyPassword) {
throw new BadRequestError('Invalid email or password!');
}
if(!authorization) {
throw new UnauthorizedError('Not authorized')
}
if() {
throw new NotFoundError('An error has occurred');
}
// your code
return res.status(201).json(user);
} catch (error) {
return next(error);
}
}
}
In the create method, several error scenarios are addressed, such as the existence of a user with the same email, invalid credentials, lack of authorization, and other general errors. Instead of handling each error individually within the controller, we can use error-handling middleware to handle all errors centrally.
Final considerations
With this, any error thrown within the UserController or other controllers will be caught by the error-handling middleware. The middleware is responsible for determining the appropriate HTTP status code and sending a JSON response with a corresponding error message.
In summary, integrating error-handling middleware into Express controllers allows for more efficient and consistent error management in your application. By centralizing error handling, you can simplify your code, making it easier to maintain and expand as your application grows.
I hope this article has demonstrated how error-handling middleware can be effectively applied in the context of Express controllers, helping you write cleaner, more modular, and more robust code in your Node.js applications.
Stackademic 🎓
Thank you for reading until the end. Before you go:
- Please consider clapping and following the writer! 👏
- Follow us X | LinkedIn | YouTube | Discord
- Visit our other platforms: In Plain English | CoFeed | Venture | Cubed
- More content at Stackademic.com