toonvanstrijp / nestjs-i18n

The i18n module for nestjs.
https://nestjs-i18n.com
Other
646 stars 111 forks source link

[GraphQL] Exception in I18nValidationPipe #603

Open DONTWARRYIMMAFINE opened 9 months ago

DONTWARRYIMMAFINE commented 9 months ago

Describe the bug

main.ts image

create-user.input.ts image

Test input: { "input": { "username": "a", "password": "12345678", } }

Result with plain ValidationPipe: image

Result with I18nValidationPipe: image

The issue is reproducible with: "@nestjs/apollo": "^12.0.11" "@nestjs/graphql": "^12.0.11"

With old packages everything works as expected: "@nestjs/apollo": "^10.2.0", "@nestjs/graphql": "^10.2.0"

Reproduction

Use any class-validator annotation on field and try to make a mutation.

System Info

System:
    OS: Linux 6.2 Ubuntu 22.04.3 LTS 22.04.3 LTS (Jammy Jellyfish)
    CPU: (16) x64 AMD Ryzen 7 7700X 8-Core Processor
    Memory: 20.91 GB / 30.49 GB
    Container: Yes
    Shell: 5.1.16 - /bin/bash
  Binaries:
    Node: 20.10.0 - ~/.nvm/versions/node/v20.10.0/bin/node
    Yarn: 1.22.21 - ~/.nvm/versions/node/v20.10.0/bin/yarn
    npm: 10.2.3 - ~/.nvm/versions/node/v20.10.0/bin/npm
  Browsers:
    Chrome: 120.0.6099.71

Used Package Manager

yarn

Validations

cain-choi commented 3 months ago

This can be resolved by changing the link as below.

exception.extensions = { errors: normalizedErrors };

But I need something custom, so I use it like below: i18n-gql-validation-exception.filter.ts

import { ArgumentsHost, Catch, ExceptionFilter } from '@nestjs/common';
import { GqlContextType } from '@nestjs/graphql';
import { I18nContext, I18nValidationException } from 'nestjs-i18n';
import { formatI18nErrors } from 'nestjs-i18n/dist/utils';

@Catch(I18nValidationException)
export class I18nGqlValidationExceptionFilter implements ExceptionFilter {
  catch(exception: any, host: ArgumentsHost) {
    if (host.getType<GqlContextType>() !== 'graphql') {
      return exception;
    }

    const i18n = I18nContext.current<I18nTranslations>(host);
    if (!i18n) {
      return exception;
    }

    const errors = formatI18nErrors(exception.errors, i18n.service, { lang: i18n.lang });
    const constraints = errors?.[0].constraints;
    if (constraints && Object.values(constraints).length > 0) {
      exception.message = Object.values(constraints)[0];
      exception.extensions = { errors };
    }

    return exception;
  }
}

main.ts

  app.useGlobalPipes(new I18nValidationPipe({ transform: true }));
  app.useGlobalFilters(new I18nGqlValidationExceptionFilter());