Валидация данных в Kotlin: обзор библиотек и практические примеры
Валидация данных — один из ключевых аспектов разработки надёжных приложений. В экосистеме Kotlin существует несколько зрелых библиотек, которые позволяют декларативно описывать правила проверки, избавляя разработчика от шаблонного кода. В этой статье мы рассмотрим три популярных инструмента: Konform, Valiktor и Kotlinx Validation, а также обсудим, когда и какой инструмент выбрать.
1. Konform — функциональная валидация на основе Arrow
Библиотека Konform построена на базе функционального фреймворка Arrow. Она использует концепцию Validated для накопления ошибок и поддерживает как простые, так и вложенные структуры данных.
Установка
// build.gradle.kts
implementation("io.konform:konform:0.4.0")
Пример использования
import io.konform.validation.*
data class User(
val name: String,
val email: String,
val age: Int
)
val userValidation = Validation<User> {
User::name {
minLength(2) hint "Имя должно содержать минимум 2 символа"
maxLength(50) hint "Имя не должно превышать 50 символов"
}
User::email {
pattern(Regex("^[\\w.-]+@[\\w.-]+\\.\\w{2,}$")) hint "Некорректный email"
}
User::age {
minimum(18) hint "Возраст должен быть не менее 18 лет"
maximum(120) hint "Укажите реальный возраст"
}
}
fun main() {
val user = User("A", "invalid-email", 15)
val result = userValidation(user)
if (result.errors.isNotEmpty()) {
result.errors.forEach { error ->
println("Поле: ${error.path} — ${error.message}")
}
} else {
println("Валидация пройдена успешно")
}
}
Особенности
- Полная интеграция с Arrow для композиции валидаций
- Поддержка вложенных объектов и списков
- Типобезопасные DSL-конструкции
- Накопление всех ошибок (не останавливается на первой)
2. Valiktor — императивная валидация с fluent API
Valiktor предлагает более традиционный подход с использованием fluent-интерфейса. Библиотека не требует функциональных зависимостей и проста в освоении для разработчиков, знакомых с Java.
Установка
implementation("org.valiktor:valiktor-core:0.12.0")
Пример использования
import org.valiktor.functions.*
import org.valiktor.validate
data class Order(
val id: String,
val amount: Double,
val items: List<String>
)
fun validateOrder(order: Order) {
validate(order) {
validate(Order::id).isNotBlank().hasSize(10..36)
validate(Order::amount).isPositive().isLessThanOrEqualTo(10000.0)
validate(Order::items).isNotEmpty().hasSize(1..50)
}
}
fun main() {
val order = Order("", -100.0, emptyList())
try {
validateOrder(order)
println("Заказ корректен")
} catch (e: Exception) {
println("Ошибка валидации: ${e.message}")
}
}
Особенности
- Простой и понятный API без функциональных абстракций
- Выбрасывает исключение при первой ошибке (режим fail-fast)
- Поддержка кастомных валидаторов через расширения
- Лёгкая интеграция с Java-проектами
3. Kotlinx Validation — официальная библиотека от JetBrains
Хотя проект Kotlinx Validation пока находится в экспериментальной стадии, он уже предлагает интересный подход с аннотациями и рефлексией, напоминающий Javax Validation (Bean Validation).
Установка
implementation("org.jetbrains.kotlinx:kotlinx-validation:0.1.0")
Пример использования
import kotlinx.validation.*
import kotlinx.validation.constraints.*
data class Product(
@get:NotBlank
val title: String,
@get:Positive
@get:Max(1000.0)
val price: Double,
@get:Size(min = 1, max = 10)
val categories: List<String>
)
fun main() {
val product = Product("", -5.0, emptyList())
val violations = validate(product)
if (violations.isNotEmpty()) {
violations.forEach { violation ->
println("${violation.propertyPath}: ${violation.message}")
}
} else {
println("Продукт валиден")
}
}