axiosnestjspugnestjs-i18n

Global interceptor, response mapping and library specific responses in NestJS


I'm trying to use "library-specific" response objects alongside a global interceptor in NestJS, but it's not working and as I understand from the documentation, this is expected:

Response mapping:

The response mapping feature doesn't work with the library-specific response strategy (using the @Res() object directly is forbidden).

The reason I'm using library specific response is because I need dynamic template rendering:

If the application logic must dynamically decide which template to render, then we should use the @Res() decorator, and supply the view name in our route handler, rather than in the @Render() decorator

And the reason I need dynamic templates is because the final template is decided based on user language (es/home, fr/home, en/home, etc). And yes, those templates have different content depending on the language (not just translated literals).

The final aim is to have 400, 500 error handling through a global interceptor. The website pulls data from an API (via axios), so when there's an error downstream, it would be supper convenient to just let it bubble up and get caught in a single place that nicely renders a 404, 500, etc.

Any ideas how to best get around this limitation?

Thanks


Solution

  • Finally managed to get what I wanted with a "catch everything" exception filter, as suggested by Jay McDoniel.

    Had to combine a couple of things from that page:

    
    import { Catch, ArgumentsHost, HttpException, HttpStatus } from '@nestjs/common';
    import { BaseExceptionFilter } from '@nestjs/core';
    import { Response, Request } from 'express'; // note the casting to Express types
    
    @Catch()
    export class AllExceptionsFilter extends BaseExceptionFilter {
        catch(exception: unknown, host: ArgumentsHost) {
    
            const ctx = host.switchToHttp();
            const response = ctx.getResponse<Response>();
            const request = ctx.getRequest<Request>();
            const httpStatus =
                exception instanceof HttpException
                    ? exception.getStatus()
                    : HttpStatus.INTERNAL_SERVER_ERROR;
    
            response.status(httpStatus);
            response.render(`views/errors/${httpStatus}`);
        }
    }
    

    And also adding the following during bootstrapping:

      const app = await NestFactory.create<NestExpressApplication>(AppModule);
      const { httpAdapter } = app.get(HttpAdapterHost);
      app.useGlobalFilters(new AllExceptionsFilter(httpAdapter));
      ...