[NestJs] Intercept axios responses and throw built-in HTTP errors for the exception filter

blminami

Narcisa

Posted on October 25, 2022

[NestJs] Intercept axios responses and throw built-in HTTP errors for the exception filter
Context

How do we intercept the external http calls made by our NestJs server, so we can log and better handle the errors?
NestJs Interceptors are able to process the requests and the responses made via the controllers, not the external http calls that we might need as part of a controller request.

Solutions

One solution would be to add a catchError on the http call. NestJs documentation provides a full example and extensive information on HttpModule and HttpService from @nestjs/axios package.

What if we already have a couple of axios requests and we don't want to add catchError block on each request? Here comes the second solution: axios response interceptors and exception filters.

First, let's consider this call as part of our service, where (hypothetically) our http call will throw an error:

//app.service.ts
getCats(): Observable<any> {
    return this.httpService.get('http://localhost:3001/cats').pipe(
      map((data) => {
        console.log('Do something');
        return data;
      }),
    );
  }
Enter fullscreen mode Exit fullscreen mode

Let's configure the axios response interceptor. We're going to add this snippet as part of the bootstrap function. All HttpService methods return an AxiosResponse wrapped in an Observable object, responses that we're going to intercept via this code:

// main.ts
import { NestFactory } from '@nestjs/core';
import { AppModule } from './app.module';
import { HttpService } from '@nestjs/axios';
import { InternalServerErrorException } from '@nestjs/common';

async function bootstrap() {
  const httpService = new HttpService();
  const app = await NestFactory.create(AppModule);

  httpService.axiosRef.interceptors.response.use(
    (response) => {
      return response;
    },
    (error) => {
      console.error('Internal server error exception', error);
      throw new InternalServerErrorException();
    },
  );

  await app.listen(3000);
}
Enter fullscreen mode Exit fullscreen mode

Responses with status 2** will be handled by the first function, where we simply return the response. In case of error, we log the error and throw a built-in HTTP exception, InternalServerErrorException. Of course, we can implement more advanced error handling here, throwing exceptions depending on the error that we get from the axios code and so on.

Next, what happens with our exception? It's going to be caught by the global http exception filter.

//http-exception.filter.ts
import { ArgumentsHost, Catch, ExceptionFilter, HttpException } from '@nestjs/common';
import { Request, Response } from 'express';

@Catch(HttpException)
export class HttpExceptionFilter implements ExceptionFilter {
  catch(exception: HttpException, host: ArgumentsHost) {
    const ctx = host.switchToHttp();
    const response = ctx.getResponse<Response>();
    const request = ctx.getRequest<Request>();
    const status = exception.getStatus();

    response.status(status).json({
      statusCode: status,
      timestamp: new Date().toISOString(),
      path: request.url
    });
  }
}
Enter fullscreen mode Exit fullscreen mode

Now that we have the code for the exception filter, let's make the adjustments so we can use it:

//app.module.ts
providers: [
    {
      provide: APP_FILTER,
      useClass: HttpExceptionFilter
    }
  ]
Enter fullscreen mode Exit fullscreen mode
//main.ts
import { NestFactory } from '@nestjs/core';
import { AppModule } from './app.module';
import { HttpService } from '@nestjs/axios';
import { HttpExceptionFilter } from './http-exception.filter';
import { InternalServerErrorException } from '@nestjs/common';

async function bootstrap() {
  const httpService = new HttpService();
  const app = await NestFactory.create(AppModule);

  //http-exception as global filter
  app.useGlobalFilters(new HttpExceptionFilter());

  httpService.axiosRef.interceptors.response.use(
    (response) => {
      return response;
    },
    (error) => {
      console.error('Internal server error exception', error);
      throw new InternalServerErrorException();
    },
  );

  await app.listen(3000);
}
Enter fullscreen mode Exit fullscreen mode

What we learned as part of this blogpost:

  • how to make an external http call via the HttpService from @nestJs/axios package
  • how to intercept the responses of the http calls and throw built-in http exceptions in case of error
  • how to intercept the http exceptions via the global http exception filter

In-depth documentation on error handling, axios interceptors and exception filters can be found here:

āœØGithub repo with the NestJs setup, exception filter and axios interceptor!

Thank you for reading! šŸ¾

šŸ’– šŸ’Ŗ šŸ™… šŸš©
blminami
Narcisa

Posted on October 25, 2022

Join Our Newsletter. No Spam, Only the good stuff.

Sign up to receive the latest update from our blog.

Related