Error handling is a crucial aspect of any production-grade application. In a Node.js-based framework like NestJS, errors can happen at any point in the application, from the server to the client-side code. Therefore, it is important to have a system in place that can handle errors in a centralized manner. This is where global error handling comes in.
In this article, we will discuss how to implement global error handling in NestJS. We will start with a brief overview of NestJS and its error-handling system. We will then move on to implementing a global error handler using NestJS’s built-in exception filters. Finally, we will explore how to customize error responses and handle unhandled exceptions.
Table of Contents
What is NestJS?
NestJS is a popular Node.js-based framework for building scalable and efficient server-side applications. It is built on top of Express and provides a modular architecture that allows developers to easily create reusable and maintainable code. NestJS also utilizes Typescript, which allows for strong typing and better code organization.
NestJS Error Handling System
NestJS provides a robust error-handling system that allows developers to handle errors in a centralized manner. The basic error handling system in NestJS includes the following components:
- Exception filters: Allows you to catch specific errors and transform them into a response that can be sent back to the client.
- Exception pipes: Allows you to transform responses that are returned from a controller or middleware.
- Interceptors: Allows you to intercept requests and responses and modify them before they reach the controller or middleware.
- Guards: Allows you to validate incoming requests before they reach the controller or middleware.
- Pipes: Allows you to manipulate incoming and outgoing data.
Implementing Global Error Handling
To implement global error handling in NestJS, we can use the built-in exception filters. Exception filters are responsible for catching specific errors and transforming them into a response that can be sent back to the client. To create a global error handler, we need to create a custom exception filter that catches all unhandled exceptions.
Here is an example of how to create a global error handler using exception filters:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 | // common/filters/global-exception.filter.ts import { Catch, ExceptionFilter, ArgumentsHost } from '@nestjs/common'; import { HttpException, HttpStatus } from '@nestjs/common'; @Catch() export class GlobalExceptionFilter implements ExceptionFilter { catch(exception: unknown, host: ArgumentsHost) { const ctx = host.switchToHttp(); const response = ctx.getResponse(); const request = ctx.getRequest(); const status = exception instanceof HttpException ? exception.getStatus() : HttpStatus.INTERNAL_SERVER_ERROR; response.status(status).json({ statusCode: status, timestamp: new Date().toISOString(), path: request.url, }); } } |
In the above code, we have created a custom exception filter called GlobalExceptionFilter
. This filter catches all unhandled exceptions by using the @Catch()
decorator without specifying any exception type.
The catch
method takes two arguments: the exception
object and the ArgumentsHost
object. The exception
object contains information about the error, while the ArgumentsHost
object contains information about the context in which the error occurred.
In the catch
method, we first extract the response
and request
objects from the ArgumentsHost
object. We then check if the exception
object is an instance of HttpException
. If it is, we get the status code of the exception. Otherwise, we set the status code to HttpStatus.INTERNAL_SERVER_ERROR
.
Finally, we send a JSON response to the client that contains the status code, timestamp, and path of the request.
To use the GlobalExceptionFilter
, we need to register it in the main.ts
file:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 | // main.ts import { NestFactory } from '@nestjs/core'; import { AppModule } from './app.module'; import { GlobalExceptionFilter } from './common/filters/global-exception.filter'; async function bootstrap() { const app = await NestFactory.create(AppModule); app.useGlobalFilters(new GlobalExceptionFilter()); await app.listen(3000); } bootstrap(); |
In the above code, we have imported the GlobalExceptionFilter
and registered it as a global filter using the useGlobalFilters
method.
Customizing Error Responses
In addition to catching unhandled exceptions, we may also want to customize the error response that is sent back to the client. We can do this by creating a custom exception class that extends the HttpException
class.
Here is an example of how to create a custom exception class:
1 2 3 4 5 6 7 8 9 10 11 | // exceptions/custom.exception.ts import { HttpException, HttpStatus } from '@nestjs/common'; export class CustomException extends HttpException { constructor(message: string) { super(message, HttpStatus.BAD_REQUEST); } } |
In the above code, we have created a custom exception class called CustomException
. This exception class extends the HttpException
class and takes a message
parameter in the constructor. We also set the status code to HttpStatus.BAD_REQUEST
.
We can then throw this exception in our controller or service:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 | // app.controller.ts import { Controller, Get, HttpException } from '@nestjs/common'; import { CustomException } from './exceptions/custom.exception'; @Controller() export class AppController { @Get() getHello(): string { throw new CustomException('Custom exception message'); } } |
In the above code, we have created a simple controller that throws a CustomException
when the /
endpoint is accessed. We can then catch this exception using our global error handler and send a customized error response to the client.
Handling Unhandled Exceptions
Sometimes, an unhandled exception may occur in our application that is not caught by any exception filter. In this case, we can use the process.on('unhandledRejection')
event to catch and handle the unhandled exception.
Here is an example of how to handle unhandled exceptions in NestJS:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 | // main.ts import { NestFactory } from '@nestjs/core'; import { AppModule } from './app.module'; import { GlobalExceptionFilter } from './common/filters/global-exception.filter'; process.on('unhandledRejection', (reason, promise) => { console.error('Unhandled Rejection at:', promise, 'reason:', reason); }); async function bootstrap() { const app = await NestFactory.create(AppModule); app.useGlobalFilters(new GlobalExceptionFilter()); await app.listen(3000); } bootstrap(); |
In the above code, we have defined a process.on('unhandledRejection')
event that catches unhandled exceptions. We then log the error to the console.
Conclusion
In this article, we have discussed how to implement global error handling in NestJS using the built-in exception filters. We have also explored how to customize error responses and handle unhandled exceptions. By implementing a global error handler, we can centralize our error-handling logic and provide a better user experience for our clients.