valiktorを使ってVO値のバリデーションを行う
今回は自身で開発・運営している「Hello Books」で利用している技術について紹介したいと思います。
Hello Booksについて
- エンジニア向け技術書レビューサービス
- 購入前の判断にエンジニアのレビューを役立てることができる
- アカウントを作成することで自身もレビューを投稿したり、技術書をブックマークしたりできる
- 詳細な条件による技術書の検索が可能
valiktorとは
Valiktor is a type-safe, powerful and extensible fluent DSL to validate objects in Kotlin.
https://github.com/valiktor/valiktor
オブジェクトのバリデーションをサポートしてくれるKotlinライブラリで、シンプルな記述で様々なバリデーションを実装できるのが魅力です。Hello BooksではDDD(ドメイン駆動設計)に基づいて設計・実装を行っていますが、Entityを構成するValue Objectを生成する際にその値の妥当性を担保するためにvaliktorを利用しています。
シンプルなBook Entityでの利用例を見てみる
一例として、下記の様な非常にシンプルなEntity "Book"を想定します。
Book |
---|
id: BookId |
author: BookAuthor |
title: BookTitle |
price: BookPrice |
publishedAt: BookPubishedAt |
Book Entityを構成する5つのValue Objectをそれぞれ定義しています。DDDでは、Entityを生成する際にはその妥当性を担保する必要があります。例えばpriceが0円以下の場合などは現実の書籍を想定するとあり得ないため、Value Object生成時にその様なケースはValidationで弾く実装を行う必要があります。
様々なアプローチがあると思いますが、valiktorを利用するとすごく簡単に実装することができます。
BookPriceでのvaliktor実装例
import org.valiktor.functions.isGreaterThan
import org.valiktor.validate
data class BookPrice(var value: Int) {
init {
validation()
}
/**
* validation rule
*/
fun validation() {
validate(this) {
validate(BookPrice::value)
.isGreaterThan(0)
.isLessThanOrEqualTo(10000)
}
}
}
Hello Booksでは抽象クラスを利用してバリデーションなどの実装を定義していますが、単純化のためクラス内で完結する実装を例として扱います。
kotlinではinit
ブロックでプライマリコンストラクタが呼び出されたときに実行される処理を定義することができます。validation
メソッドでvaliktorを用いたバリデーションを実装しています。メソッドチェインの形で複数条件を設定することができ、今回のケースでは"書籍の価格は0円以上10,000円以下でなければいけない"としてバリデーションを設定しています。
ユニットテストでバリデーションの実装を確認
import org.junit.jupiter.api.assertDoesNotThrow
import org.junit.jupiter.api.assertThrows
import org.junit.jupiter.params.ParameterizedTest
import org.junit.jupiter.params.provider.Arguments
import org.junit.jupiter.params.provider.MethodSource
import org.valiktor.ConstraintViolationException
class BookPriceTest {
companion object {
/**
* data provider methods for "testValidation"
*/
@JvmStatic
fun dataProvider() = listOf(
// normal cases
Arguments.of(1, true),
Arguments.of(100000, true),
// exceptional cases
Arguments.of(0, false),
)
}
/**
* validation test checking if provided parameters are valid for the VO
*/
@ParameterizedTest
@MethodSource("dataProvider")
fun testValidation(value: Int, isValid: Boolean) {
when (isValid) {
true -> assertDoesNotThrow { BookPrice(value) }
false -> assertThrows<ConstraintViolationException> { BookPrice(value) }
}
}
}
junitのParameterizedTestを利用することでdataProvider
で定義している各値でBookPrice
インスタンスを生成した場合にバリデーション例外が発生するかを確認しています。データドリブンテストについてはこちらの記事詳しく紹介しています。
実際にテストを走らせると、通過したことを無事確認できました!
今回は数字の上下限に対するバリデーション実装のみ扱いましたが、他にもhasSize
で最小/最大長を設定したり、.isEmail()
でメールアドレス形式を保証したりなど様々な機能を利用することができます。公式のドキュメントで分かりやすくまとめられているので、興味のある方は見てみてください。
最後に
最後まで読んでくださり、ありがとうございました。よろしければHello Booksにも是非遊びに来てください!
Author And Source
この問題について(valiktorを使ってVO値のバリデーションを行う), 我々は、より多くの情報をここで見つけました https://qiita.com/Takuyaaaa/items/32cca66d57a5a5934b26著者帰属:元の著者の情報は、元のURLに含まれています。著作権は原作者に属する。
Content is automatically searched and collected through network algorithms . If there is a violation . Please contact us . We will adjust (correct author information ,or delete content ) as soon as possible .