【问题标题】:How to handle TypeORM entity field unique validation error in NestJS?如何处理 NestJS 中的 TypeORM 实体字段唯一验证错误?
【发布时间】:2018-07-28 19:13:42
【问题描述】:

我在我的 TypeORM 实体字段电子邮件上设置了一个自定义唯一验证器装饰器。 NestJS有依赖注入,但是服务没有注入。

错误是:

TypeError: Cannot read property 'findByEmail' of undefined

对实现自定义电子邮件验证器有任何帮助吗?

user.entity.ts:

@Column()
@Validate(CustomEmail, {
    message: "Title is too short or long!"
})
@IsEmail()
email: string;

我的CustomEmail 验证器是

import {ValidatorConstraint, ValidatorConstraintInterface, 
ValidationArguments} from "class-validator";
import {UserService} from "./user.service";

@ValidatorConstraint({ name: "customText", async: true })
export class CustomEmail implements ValidatorConstraintInterface {

  constructor(private userService: UserService) {}
  async validate(text: string, args: ValidationArguments) {

    const user = await this.userService.findByEmail(text);
    return !user; 
  }

  defaultMessage(args: ValidationArguments) { 
    return "Text ($value) is too short or too long!";
  }
}

我知道我可以在Column 选项中设置unique

@Column({
  unique: true
})

但这会引发 mysql 错误和导致我的应用程序崩溃的ExceptionsHandler,所以我无法自己处理它...

谢谢!

【问题讨论】:

  • 您不能在 ValidatorConstraint 类中注入依赖项。它不是 Nest 容器的一部分。

标签: typeorm nestjs


【解决方案1】:

我可以在这里提出两种不同的方法,第一种在本地捕获约束违规错误而无需额外的请求,第二种使用全局错误过滤器,在整个应用程序中捕获此类错误。我个人使用后者。

本地no-db请求解决方案

无需进行额外的数据库请求。您可以捕获违反唯一约束的错误并将您想要的任何HttpException 扔给客户端。在users.service.ts:

  public create(newUser: Partial<UserEntity>): Promise<UserEntity> {
    return this.usersRepository.save(newUser).catch((e) => {
      if (/(email)[\s\S]+(already exists)/.test(e.detail)) {
        throw new BadRequestException(
          'Account with this email already exists.',
        );
      }
      return e;
    });
  }

哪个会返回:

全局错误过滤解决方案

甚至创建一个全局 QueryErrorFilter:

@Catch(QueryFailedError)
export class QueryErrorFilter extends BaseExceptionFilter {
  public catch(exception: any, host: ArgumentsHost): any {
    const detail = exception.detail;
    if (typeof detail === 'string' && detail.includes('already exists')) {
      const messageStart = exception.table.split('_').join(' ') + ' with';
      throw new BadRequestException(
        exception.detail.replace('Key', messageStart),
      );
    }
    return super.catch(exception, host);
  }
}

然后在main.ts:

async function bootstrap() {
  const app = await NestFactory.create(/**/);
  /* ... */
  const { httpAdapter } = app.get(HttpAdapterHost);
  app.useGlobalFilters(new QueryErrorFilter(httpAdapter));
  /* ... */
  await app.listen(3000);
}
bootstrap();

这将给出通用的$table entity with ($field)=($value) already exists. 错误消息。示例:

【讨论】:

  • 似乎是一个很好的解决方案恕我直言,尤其是全局过滤器。使用 exception = new BadRequestException(...) 而不是 throw 让它工作,立即抛出它确实会导致丢失返回给客户端的每个异常。
【解决方案2】:

我修改了我的代码。我正在检查用户服务(而不是自定义验证器)中用户名/电子邮件的唯一性,并在用户已插入数据库的情况下返回 HttpExcetion。

【讨论】:

    猜你喜欢
    • 2020-03-18
    • 1970-01-01
    • 2016-10-22
    • 2019-07-08
    • 1970-01-01
    • 1970-01-01
    • 2018-10-25
    • 1970-01-01
    • 2020-09-03
    相关资源
    最近更新 更多