Skip to content

Valiktor 導入メモ #10

@keyskey

Description

@keyskey

Valiktorとは

オブジェクトに対する典型的なバリデーションロジックをシュッと書くためのDSLを提供してくれるやつ。
RailsでいうところのActiveModel::Validation に相当するライブラリ。

何を依存に追加すればいいの

使いどころは?

  1. Entityのコンストラクタ内にバリデーションロジックを書く (Railsでいうモデルのバリデーション)
  2. Usecaseでリポジトリの更新系メソッドを呼ぶ前に引数のバリデーションロジックを書く (RailsでいうForm object のバリデーション)

辺り。

バリデーションエラーどう表示されるの?

ただvalidate メソッドを呼ぶだけでは以下のような何のありがたみもないエラーが返ってくる。

{
  "errors": [
    {
      "message": "Exception while fetching data (/updateUser) : null",
      "locations": [
        {
          "line": 2,
          "column": 3
        }
      ],
      "path": [
        "updateUser"
      ]
    }
  ]
}

せめてどの属性がどのバリデーションに引っかかったのかくらいは出すようにしたいので、以下のような拡張を入れ込む。

fun <T> Result<T>.throwOnFailure() {
    if (this.isFailure) {
        val errorMessage = (this.exceptionOrNull() as ConstraintViolationException).getMessage()
        throw IllegalArgumentException(errorMessage)
    }
}

fun ConstraintViolationException.getMessage(): String {
    return this.constraintViolations
        .mapToMessage(locale = Locale.ENGLISH)
        .joinToString(separator = ",") { "${it.property}: ${it.message}" }
}

data class User(
    val id: Int,
    val name: String,
    val createdAt: LocalDateTime,
    val updatedAt: LocalDateTime
) {
    init {
        runCatching {
            validate(this) {
                validate(User::id).isPositive()
                validate(User::name).hasSize(min = 1, max = 20)
            }
        }.throwOnFailure()
    }
}

これでMutationクエリなどでUserを無効な値で更新しようとしたら以下のようなエラーが返ってくるようになる。

{
  "errors": [
    {
      "message": "Exception while fetching data (/updateUser) : name: Size must be between 1 and 20",
      "locations": [
        {
          "line": 2,
          "column": 3
        }
      ],
      "path": [
        "updateUser"
      ]
    }
  ]
}

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions