Lesson 4
Error Handling in NestJS
Introduction to Error Handling

Welcome to this lesson on Error Handling in NestJS. So far, we've learned how to integrate MongoDB, transform data store objects to DTOs, and configure middleware in our NestJS application. Today, we'll focus on error handling, a critical aspect of building robust and user-friendly applications. Effective error handling ensures that our application can gracefully manage errors and provide meaningful feedback to users.

By the end of this lesson, you will be able to set up error handling for a NestJS application, create and use exception filters, and test various error scenarios to ensure your application handles errors as expected.

Setting Up Error Handling in NestJS

To handle errors effectively, NestJS provides a powerful mechanism called Exception Filters. These filters allow you to manage exceptions and provide custom error responses.

Now, let's move to the heart of our error handling approach: creating an Exception Filter.

Creating an Exception Filter
Understanding Exception Filters in NestJS

Exception Filters in NestJS allow you to catch unhandled exceptions in your application and modify the response that users receive.

Step-by-Step Guide to Create `HttpExceptionFilter`

We'll walk through the process of creating an HttpExceptionFilter.

Step 1: Import Required Modules Create a new file named http-exception.filter.ts and start by importing the necessary modules:

TypeScript
1import { ExceptionFilter, Catch, ArgumentsHost, HttpException, HttpStatus } from '@nestjs/common'; 2import { Request, Response } from 'express';

Step 2: Define the HttpExceptionFilter Class Next, we define the exception filter class:

TypeScript
1@Catch(HttpException) 2export class HttpExceptionFilter implements ExceptionFilter { 3 catch(exception: HttpException, host: ArgumentsHost) { 4 const ctx = host.switchToHttp(); 5 const response = ctx.getResponse<Response>(); 6 const request = ctx.getRequest<Request>(); 7 const status = exception.getStatus(); 8 9 const errorResponse = { 10 statusCode: status, 11 timestamp: new Date().toISOString(), 12 path: request.url, 13 }; 14 15 if (status === HttpStatus.INTERNAL_SERVER_ERROR) { 16 response.status(status).json(errorResponse); 17 } else { 18 response.status(status).json({ 19 ...errorResponse, 20 message: exception.message, 21 }); 22 } 23 } 24}

Explanation:

  • @Catch(HttpException) decorator tells NestJS to use this filter for HttpExceptions.
  • The catch method handles the exception, extracts the relevant details (status, request URL), and constructs a response.
  • Different responses for internal server errors and other types of errors ensure relevant information is sent back to the client.
Integrating Exception Filter in App

Next, we'll integrate our HttpExceptionFilter into the application.

Step 1: Modify app.module.ts Edit app.module.ts to add the filter:

TypeScript
1import { Module, MiddlewareConsumer, NestModule } from '@nestjs/common'; 2import { APP_FILTER } from '@nestjs/core'; 3import { MongooseModule } from '@nestjs/mongoose'; 4import { TodoModule } from './todo/todo.module'; 5import { ValidationMiddleware } from './middlewares/validation.middleware'; 6import { TimerMiddleware } from './middlewares/timer.middleware'; 7import { HttpExceptionFilter } from './filters/http-exception.filter'; 8 9@Module({ 10 imports: [ 11 MongooseModule.forRoot('mongodb://localhost/nestjs-todo'), 12 TodoModule, 13 ], 14 providers: [ 15 { 16 provide: APP_FILTER, 17 useClass: HttpExceptionFilter, 18 } 19 ] 20}) 21export class AppModule implements NestModule { 22 configure(consumer: MiddlewareConsumer) { 23 consumer 24 .apply(TimerMiddleware) 25 .forRoutes('*'); 26 } 27}

Explanation:

  • The APP_FILTER token from @nestjs/core registers the HttpExceptionFilter globally.
  • Middleware configurations ensure that ValidationMiddleware and TimerMiddleware apply to specified routes.
Testing and Demonstrating Error Handling
Sample Code to Simulate Various Errors

To ensure our error handling works, we’ll simulate different errors. Create a send_request.ts script with sample code:

TypeScript
1import axios from 'axios'; 2 3// Create a new todo item 4async function createTodo() { 5 try { 6 const response = await axios.post('http://localhost:3000/todos', { 7 title: 'Learn NestJS', 8 description: 'Explore the basics of NestJS' 9 }); 10 return response.data; 11 } catch (error) { 12 if (error.response) { 13 console.log(`HTTP ${error.response.status}: `, error.response.data); 14 } 15 } 16} 17 18// Create a new todo item with invalid data 19async function createInvalidTodo() { 20 try { 21 await axios.post('http://localhost:3000/todos', { 22 title: '' // Invalid title 23 }); 24 } catch (error) { 25 if (error.response) { 26 console.log(`HTTP ${error.response.status}: `, error.response.data); 27 } 28 } 29} 30 31// Simulate internal server error 32async function simulateInternalServerError() { 33 try { 34 await axios.get('http://localhost:3000/error'); 35 } catch (error) { 36 if (error.response) { 37 console.log(`HTTP ${error.response.status}: `, error.response.data); 38 } 39 } 40} 41 42// Get all todo items 43async function getTodos() { 44 const response = await axios.get('http://localhost:3000/todos'); 45 console.log('Todos:', response.data); 46} 47 48async function run() { 49 try { 50 console.log('Running database migration'); 51 execSync('npm run typeorm migration:run'); 52 53 console.log('Creating a valid todo'); 54 await createTodo(); 55 56 console.log('Creating an invalid todo'); 57 await createInvalidTodo(); 58 59 console.log('Simulating internal server error'); 60 await simulateInternalServerError(); 61 62 console.log('Getting all todos'); 63 await getTodos(); 64 } catch (error) { 65 console.error('Error during run:', error.message); 66 } 67} 68 69run();
Running Tests to Verify Error Handling

Explanation:

  • Creating a valid ToDo item: Normal scenario; should return success.
  • Creating an invalid ToDo item: Triggers validation error; ensures ValidationMiddleware and HttpExceptionFilter work.
  • Simulating internal server error: Triggers server-side error handling; ensures server responses are customized.
  • Getting all ToDo items: Verifies CRUD operations continue to function.

Expected output examples from running the script:

Bash
1$ Creating a valid todo 2$ Creating an invalid todo 3$ HTTP 400: { statusCode: 400, timestamp: '2023-02-23T12:34:56.789Z', path: '/todos', message: 'Validation failed' } 4$ Simulating internal server error 5$ HTTP 500: { statusCode: 500, timestamp: '2023-02-23T12:34:56.789Z', path: '/todos/error' } 6$ Getting all todos 7$ Todos: [ ...list of todo items... ]
Summary and Next Steps

In this lesson, we've covered the essentials of error handling in NestJS. You learned how to:

  1. Set up error handling using Exception Filters.
  2. Create an HttpExceptionFilter to manage exceptions.
  3. Integrate the filter into your application.
  4. Test various error scenarios to ensure robust error management.

Next, you'll get the chance to solidify your understanding through hands-on practice exercises. These exercises will involve creating error scenarios and verifying that your application handles them gracefully.

Congratulations on completing this course! You've taken significant steps toward mastering NestJS and building robust, enterprise-ready applications. Keep practicing and applying what you've learned, and you'll continue to grow as a developer. Happy coding!

Enjoy this lesson? Now it's time to practice with Cosmo!
Practice is how you turn knowledge into actual skills.