打字稿,DDD:验证

时间:2021-04-17 18:26:04

标签: typescript domain-driven-design

我一直在研究有关输入验证的很多内容,但我有点困惑,许多人表示将验证类型大小、域中特定变量的类型,以不会导致验证的方式执行验证领域知识的泄漏 很好,因为我正在使用打字稿,我想到了一个静态函数来创建我的聚合并使用一个名为 canBuild 的静态函数来验证是否可以创建聚合

像这样:

export class PersonAggregrate extends Entity<IPersonProps> {
  private constructor(props: IPersonProps, id?: string) {
    super(props, id)
  }

  private static canBuild(props: IPersonJSON): IErrorModel[] {
    let errors = [] as IErrorModel[]
    if (typeof props.firstName !== 'string') errors.push({})
    if (typeof props.lastName !== 'string') errors.push({})
    if (props.firstName.length < 4) errors.push({})
    if (props.lastName.length < 2) errors.push({})
    return errors
  }

  public static build(
    props: IPersonJSON & { id?: string },
  ): Either<IErrorModel[], Person> {
    const hasErrs = this.canBuild(props)
    const user = User.build(props.user)
    if (user.isLeft()) {
      hasErrs.push(...user.value)
      return left(hasErrs)
    }
    if (hasErrs.length > 0) return left(hasErrs)
    const person = new Person({ ...props, user: user.value }, props.id)
    return right(person)
  }
}

用户实体:

export class User extends Entity<IUserJSON> {
  private constructor(props: IUserJSON, id?: string) {
    super(props, id)
  }

  private static canBuild(user: IUserJSON) {
    let errors = [] as IErrorModel[]
    if (typeof user.login !== 'string') errors.push({})
    if (typeof user.password !== 'string') errors.push({})
    if (user.refreshToken && !validator.isJWT(user.refreshToken)) {
      errors.push({})
    }
    return errors
  }

  public static build(
    props: IUserJSON & { id?: string },
  ): Either<IErrorModel[], User> {
    const canBuild = this.canBuild(props)
    if (canBuild.length > 0) left(canBuild)
    const user = new User(props, props.id)
    return right(user)
  }
}

我的用户实体是我聚合人的一部分

我是否也在我的命令中执行了以下操作来创建聚合:

export class CreatePersonCommand implements ICommand {
  private readonly id: string
  private readonly login!: string
  private readonly password!: string
  private readonly personId!: string
  private readonly firstName!: string
  private readonly lastName!: string

  constructor(person: Omit<IPersonJSON & IUserJSON, 'user' | 'personId'>) {
    this.id = v4()
    this.personId = this.id
    this.login = person.login
    this.password = person.password
    this.firstName = person.firstName
    this.lastName = person.lastName
  }

  public CanExecute(): boolean {
    let errors = [] as IErrorModel[]
    for (let field in this) {
      if (!this[field]){
        errors.push({ code: 215, message: `Required field: ${field}` })
      }
    }
    if (errors.length > 0) throw new BadRequestERROR({ errors })
    return errors.length <= 0
  }
}

不允许将数据发送到没有聚合属性的实体

export class CreatePersonCommand implements ICommand {
  private readonly id: string
  private readonly login!: string
  private readonly password!: string
  private readonly personId!: string
  private readonly firstName!: string
  private readonly lastName!: string

  constructor(person: Omit<IPersonJSON & IUserJSON, 'user' | 'personId'>) {
    this.id = v4()
    this.personId = this.id
    this.login = person.login
    this.password = person.password
    this.firstName = person.firstName
    this.lastName = person.lastName
  }

  public CanExecute(): boolean {
    let errors = [] as IErrorModel[]
    for (let field in this) {
      if (!this[field]){
        errors.push({ code: 215, message: `Required field: ${field}` })
      }
    }
    if (errors.length > 0) throw new BadRequestERROR({ errors })
    return errors.length <= 0
  }
}

在我的汇总中,我不使用 throw in errors 因为它们只是输入数据错误,但我不知道是否应该考虑它(空数据作为未处理的输入数据,因为它们没有被发送) 在我的中介上,我在执行命令之前使用 canExecute:

public publish<T extends ICommand>(command: T): Promise<any> {
    if (!command) throw new InvalidCommandException()
    const handler = this.registry.get(command.constructor.name)
    if (!handler) throw new HandlerNotFoundException(command.constructor.name)
    if(!command.CanExecute()) throw new InvalidCommandException()
    return handler.execute(command)
  }

我想知道这是正确的还是有更好的选择?

0 个答案:

没有答案