Search code examples
exceptionconfigurationnestjsinternal-server-error

How can I configure NestJS to continue after it has encountered an exception?


I'm using NestJS 10. I start my server locally using

npm run start:dev

which is defined in my package.json as

"start:dev": "nest start --watch",

Having an issue where if a controller method throws an exception, the server is unable to respond to any other request. For example, I have this controller method ...

@Controller(ORDERS_CONTEXT_PATH)
export class OrdersController {
  constructor(private readonly ordersService: OrdersService) {}

  @UseGuards(OptionalAccessTokenGuard)
  @Post('paymentIntent')
  createPaymentIntent(
    @Req() req: Request,
    @Body() createOrderItemDtos: CreateOrderItemDto[],
  ): Promise<PaymentIntent> {
    const userId = req.user ? req.user['sub'] : null;
    return this.ordersService.createPaymentIntent(userId, createOrderItemDtos);
  }

If the underlying service throws an exception, the NestJS console reports it ...

/Users/myuser/Documents/workspace/myproject/src/orders/orders.service.ts:43
      createOrderDto.orderItems.map(async (orderItemDto) => {
                                ^
TypeError: Cannot set properties of undefined (setting 'id')
    at /Users/myuser/Documents/workspace/myproject/src/orders/orders.service.ts:47:18
    at Array.map (<anonymous>)
    at OrdersService.create (/Users/myuser/Documents/workspace/myproject/src/orders/orders.service.ts:43:33)
    at runOriginal (/Users/myuser/Documents/workspace/myproject/node_modules/typeorm-transactional/src/transactions/wrap-in-transaction.ts:53:34)
    at OrdersService.<anonymous> (/Users/myuser/Documents/workspace/myproject/node_modules/typeorm-transactional/src/transactions/wrap-in-transaction.ts:117:20)
    at step (/Users/myuser/Documents/workspace/myproject/node_modules/typeorm-transactional/dist/transactions/wrap-in-transaction.js:33:23)
    at Object.next (/Users/myuser/Documents/workspace/myproject/node_modules/typeorm-transactional/dist/transactions/wrap-in-transaction.js:14:53)
    at /Users/myuser/Documents/workspace/myproject/node_modules/typeorm-transactional/dist/transactions/wrap-in-transaction.js:8:71
    at new Promise (<anonymous>)
    at __awaiter (/Users/myuser/Documents/workspace/myproject/node_modules/typeorm-transactional/dist/transactions/wrap-in-transaction.js:4:12)

but now whenever I make other requests (even to different controllers), I repeatedly get

Error: connect ECONNREFUSED 127.0.0.1:3000

back from the server. Is there a general way I configure my server to return a 500 if there is an underlying problem and allow it to continue to handle client requests?


Solution

  • the problem is in exception occurs during the processing of a request, the server may go into a failed state, making subsequent requests fail as well.

    One solution to this issue is to add a global exception filter to your NestJS application. This filter will catch any unhandled exceptions and respond with an appropriate error status code, allowing the server to continue processing other requests. You can create a global exception filter by implementing the ExceptionFilter interface.

    Example :

    // create a file, e.g., global-exception.filter.ts
    
    import {
      ExceptionFilter,
      Catch,
      ArgumentsHost,
      HttpException,
      HttpStatus,
    } from '@nestjs/common';
    import { Request, Response } from 'express';
    
    @Catch()
    export class GlobalExceptionFilter implements ExceptionFilter {
      catch(exception: any, host: ArgumentsHost) {
        const ctx = host.switchToHttp();
        const response = ctx.getResponse<Response>();
        const request = ctx.getRequest<Request>();
    
        const status =
          exception instanceof HttpException
            ? exception.getStatus()
            : HttpStatus.INTERNAL_SERVER_ERROR;
    
        response.status(status).json({
          statusCode: status,
          timestamp: new Date().toISOString(),
          path: request.url,
          message: 'Internal Server Error', // You can customize this message
        });
      }
    }
    

    Then, you need to apply this filter globally in your main application file (e.g., main.ts):

    import { NestFactory } from '@nestjs/core';
    import { AppModule } from './app.module';
    import { GlobalExceptionFilter } from './path/to/global-exception.filter';
    
    async function bootstrap() {
      const app = await NestFactory.create(AppModule);
    
      // Apply the global exception filter
      app.useGlobalFilters(new GlobalExceptionFilter());
    
      await app.listen(3000);
    }
    bootstrap();