Md. Moniruzzaman
Md. Moniruzzaman

Reputation: 657

How to modify HTTPException message in nestjs graphql exception filters?

I want to use localization in the class-validator error message in nestjs graphql. But I am unable to set the translated message in response and return that back. I have tried many solutions like response.status(400).json({....}) for sending modified response but that did not work,

I have used,

 providers: [
{
  provide: APP_FILTER,
  useClass: AllExceptionFilter,
},

],

and my AllExceptionFilter.ts is

import { Catch, ArgumentsHost, BadRequestException } from '@nestjs/common';
import { GqlExceptionFilter, GqlArgumentsHost } from '@nestjs/graphql';
import { I18nService } from 'nestjs-i18n';

@Catch(BadRequestException)
export class AllExceptionFilter implements GqlExceptionFilter {
  constructor(private readonly i18n: I18nService) {}

  async catch(exception: BadRequestException, host: ArgumentsHost) {
   const gqlHost = GqlArgumentsHost.create(host);

    const translatedMessage = await this.i18n.translate('validation.NotEmpty', {
       lang: 'en',
      });


     // In this place I want the modifications and then return the newexception object.

     return exception;
  }
}

I want to modify the exception messages with translated messages.

Like this is the result of console.log(exception.getResponse());

    {
      statusCode: 400,
      message: [
        'password must be longer than or equal to 8 characters',
        'Both "passwordConfirm" and "password" fields are not Matched!'
      ],
      error: 'Bad Request'
    }

But I want that message array messages with the translated message, something like I need a function like exception.setResponse({message:['Translated Message', 'Translated Message2']}). or something like I will construct an object then recreate this exception object.

The final output of console.log(exception.getResponse()); then will be like

   {
      statusCode: 400,
      message: [
        'Translated Message',
        'Translated Message 2'
      ],
      error: 'Bad Request'
    }

and the exception object that I am returning will be with this translated message.

How to do this? or is there any better way to use localization for nestjs-i18next with graphql to translate the class-validator error message or HTTPException Error Messages?

Upvotes: 11

Views: 4937

Answers (1)

touri
touri

Reputation: 169

As the main docs of nestjs-i18n mentioned:

If you want a different output, create your own interceptor! For an example look at the I18nValidationExceptionFilter.

You can customize and return your own exception like this:

@Catch(I18nValidationException)
export class I18nValidationExceptionFilter implements ExceptionFilter {
    constructor(
        private readonly options: I18nValidationExceptionFilterOptions = {
            detailedErrors: true,
        },
    ) {}
    catch(exception: I18nValidationException, host: ArgumentsHost) {
        const i18n = I18nContext.current();

        const errors = formatI18nErrors(exception.errors ?? [], i18n.service, {
            lang: i18n.lang,
        });

        switch (host.getType() as string) {
            case 'http':
                const response = host.switchToHttp().getResponse();
                response
                    .status(
                        this.options.errorHttpStatusCode ||
                            exception.getStatus(),
                    )
                    .send({
                        statusCode:
                            this.options.errorHttpStatusCode ||
                            exception.getStatus(),
                        message: exception.getResponse(),
                        errors: this.normalizeValidationErrors(errors),
                    });
                break;
            case 'graphql':
                const normalizedErrors = this.normalizeValidationErrors(errors);
                // return new exception here
                return new BadRequestException(normalizedErrors[0]);
        }
    }
...

Also, make sure that you set detailedErrors value to false:

app.useGlobalFilters(
        new I18nValidationExceptionFilter({
            detailedErrors: false,
        }),
    );

In my sample code, i returned my first error message. If you want to return whole object, maybe you need to stringify it before return.

Upvotes: 0

Related Questions