Exception Filters: Centralized Error Handling in NestJS

In any application, error handling is critical for ensuring that users receive meaningful feedback when things go wrong. In NestJS, exception filters are a powerful tool that allow you to manage errors in a centralized, consistent way across your entire application.

In this module, we’ll explore how to use exception filters in NestJS to handle errors globally or locally. We’ll look at how to define custom exception filters, use built-in exceptions, and create a unified error-handling strategy for your NestJS application.

Table of Contents

  1. Introduction
  2. What are Exception Filters in NestJS?
  3. Default Error Handling in NestJS
  4. Creating a Custom Exception Filter
  5. Using Built-in Exception Filters
  6. Applying Exception Filters Globally and Locally
  7. Customizing the Response Format
  8. Best Practices for Exception Handling
  9. Conclusion

Introduction

In every application, errors can occur for various reasons: user input issues, server failures, or network problems. Handling these errors in a way that makes sense to users is critical for a good user experience.

NestJS offers a flexible exception filter mechanism that enables you to manage errors consistently across your entire application. Exception filters in NestJS allow you to catch and transform errors before they are sent to the client, ensuring that your application provides clear and informative error messages.

This module will cover the fundamentals of exception filters in NestJS and demonstrate how to set up centralized error handling for your application.

What are Exception Filters in NestJS?

In NestJS, an exception filter is a class responsible for handling and formatting errors. It provides a way to catch unhandled exceptions and return a custom response. Exception filters are particularly useful when you want to:

  • Catch exceptions thrown by the framework, such as HttpException or BadRequestException.
  • Handle application-specific exceptions and format them consistently.
  • Implement centralized error-handling logic for your entire application.

Key Concepts of Exception Filters:

  • Custom Filters: You can create custom filters to handle specific errors.
  • Global and Local Filters: Filters can be applied globally or at the controller or method level.
  • Built-in Exception Filters: NestJS provides built-in exception filters to handle standard HTTP errors.

Default Error Handling in NestJS

By default, NestJS uses a built-in exception filter that catches all exceptions, formats them into a consistent response, and sends them to the client.

For example, if you throw a BadRequestException, NestJS will automatically respond with a 400 HTTP status code and a message:

{
"statusCode": 400,
"message": "Bad Request",
"error": "Bad Request"
}

While this default behavior is useful, you may want to customize error responses to better suit your application’s needs, provide additional information, or log the errors.

Creating a Custom Exception Filter

Creating a custom exception filter allows you to catch specific errors and handle them in a tailored way. Here’s how to create and use a custom exception filter in NestJS:

Step 1: Create a Custom Exception Filter

To create a custom exception filter, you need to implement the ExceptionFilter interface and the catch method. The catch method is responsible for handling the exception.

Here’s an example of a custom exception filter that handles all NotFoundException errors:

import { ExceptionFilter, Catch, ArgumentsHost } from '@nestjs/common';
import { Response } from 'express';
import { NotFoundException } from '@nestjs/common';

@Catch(NotFoundException)
export class NotFoundExceptionFilter implements ExceptionFilter {
catch(exception: NotFoundException, host: ArgumentsHost) {
const response = host.switchToHttp().getResponse<Response>();
const status = exception.getStatus();

response.status(status).json({
statusCode: status,
message: 'Resource not found',
error: 'Not Found',
});
}
}

Step 2: Use the Custom Exception Filter

You can apply the custom filter either globally or locally.

Apply Filter Globally

To apply the filter globally, modify your main.ts file as follows:

import { NestFactory } from '@nestjs/core';
import { AppModule } from './app.module';
import { NotFoundExceptionFilter } from './filters/not-found-exception.filter';

async function bootstrap() {
const app = await NestFactory.create(AppModule);
app.useGlobalFilters(new NotFoundExceptionFilter());
await app.listen(3000);
}

bootstrap();

Apply Filter Locally

To apply the filter only to specific controllers or route handlers, use the @UseFilters() decorator:

import { Controller, Get, UseFilters } from '@nestjs/common';
import { NotFoundExceptionFilter } from './filters/not-found-exception.filter';

@Controller('users')
@UseFilters(NotFoundExceptionFilter)
export class UserController {
@Get()
findUser() {
throw new NotFoundException();
}
}

Using Built-in Exception Filters

NestJS provides several built-in exception filters that can be used out of the box. These filters handle common HTTP errors such as NotFoundException, BadRequestException, UnauthorizedException, and others.

Example: Using the Built-in HttpException Filter

NestJS automatically handles all HttpException errors, including those that extend it, like BadRequestException, UnauthorizedException, etc.

Here’s an example of throwing a BadRequestException:

import { BadRequestException } from '@nestjs/common';

throw new BadRequestException('Invalid input data');

NestJS will automatically respond with a 400 status code and a custom error message:

{
"statusCode": 400,
"message": "Invalid input data",
"error": "Bad Request"
}

These built-in filters can be customized using custom exception filters or by extending NestJS’s exception classes.

Applying Exception Filters Globally and Locally

You can apply exception filters globally or locally in NestJS.

Global Exception Filters

Global exception filters can be applied in the main.ts file, which affects the entire application. This is useful for handling common errors in a standardized way across all controllers.

app.useGlobalFilters(new NotFoundExceptionFilter());

Local Exception Filters

Local exception filters are applied at the controller or route handler level using the @UseFilters() decorator. This allows you to handle errors differently depending on the controller or action.

import { Controller, Post, UseFilters } from '@nestjs/common';
import { BadRequestExceptionFilter } from './filters/bad-request-exception.filter';

@Controller('users')
@UseFilters(BadRequestExceptionFilter)
export class UserController {
@Post()
createUser() {
throw new BadRequestException('Invalid user data');
}
}

Customizing the Response Format

By default, NestJS exception filters return a generic error format with statusCode, message, and error fields. You can customize the format of the response by modifying the response object in your custom filter.

Here’s an example of a custom error response format:

@Catch(HttpException)
export class CustomExceptionFilter implements ExceptionFilter {
catch(exception: HttpException, host: ArgumentsHost) {
const response = host.switchToHttp().getResponse<Response>();
const status = exception.getStatus();
const errorResponse = {
code: status,
message: exception.message,
timestamp: new Date().toISOString(),
path: host.switchToHttp().getRequest().url,
};

response.status(status).json(errorResponse);
}
}

In this example, we’ve added a timestamp and path to the error response, giving the client more context about the error.

Best Practices for Exception Handling

  1. Use Built-in Exception Filters: NestJS provides many useful built-in exception filters that cover common HTTP error cases, such as NotFoundException, BadRequestException, and UnauthorizedException.
  2. Create Custom Filters for Specific Use Cases: Create custom exception filters when you need to handle specific types of errors or format responses in a unique way.
  3. Use Global Exception Filters: Apply exception filters globally in main.ts to ensure a consistent error-handling strategy across your application.
  4. Handle Specific Errors Locally: Apply exception filters locally when different controllers or routes need different error-handling logic.
  5. Log Errors for Debugging: Always log errors when possible, especially in production environments, to aid debugging and support.

Conclusion

Exception filters in NestJS provide a flexible and consistent way to handle errors. By creating custom filters or using the built-in ones, you can ensure that your application catches and formats errors in a meaningful way for your users. Centralized error handling improves both the user experience and the maintainability of your application by providing a clear structure for error responses.

Now that you understand how to use exception filters, you can implement a comprehensive error-handling strategy in your NestJS application, ensuring that errors are handled gracefully and consistently.