Валидация данных в Kotlin: библиотеки и подходы (Kotlin, Java)

Онлайн-тренажер Python для начинающих

Изучайте Python легко и без перегрузки теорией. Решайте практические задачи с автоматической проверкой, получайте подсказки на русском языке и пишите код прямо в браузере — без необходимости что-либо устанавливать.

Начать курс

Валидация данных в Kotlin: обзор библиотек и практические примеры

Валидация данных — один из ключевых аспектов разработки надёжных приложений. В экосистеме Kotlin существует несколько мощных библиотек, которые позволяют декларативно описывать правила проверки, избегая громоздких условных конструкций. В этой статье мы рассмотрим три популярных инструмента: Konad, Valiktor и Kvalidation. Вы узнаете, как они работают, и увидите примеры кода для реальных задач.

1. Konad — функциональная валидация

Konad (Kotlin Validation) использует концепцию монад и функционального программирования. Вместо выбрасывания исключений библиотека возвращает Validated<E, A>, где E — тип ошибки, а A — успешное значение. Это позволяет накапливать ошибки и обрабатывать их без side-эффектов.

Установка

// build.gradle.kts
dependencies {
    implementation("io.github.mkobit:konad:0.3.0")
}

Пример использования

import konad.*

data class User(val name: String, val age: Int)

fun validateUser(user: User): Validated<String, User> {
    return Validated.valid(user)
        .validate { it.name.isNotBlank() } { "Name cannot be blank" }
        .validate { it.age in 18..99 } { "Age must be between 18 and 99" }
}

fun main() {
    val user = User("Alice", 25)
    val result = validateUser(user)

    when (result) {
        is Valid -> println("Valid user: ${result.value}")
        is Invalid -> println("Errors: ${result.errors.joinToString(", ")}")
    }
}

Преимущества Konad:

  • Чистый функциональный стиль без исключений
  • Накапливание всех ошибок валидации
  • Композиция валидаторов

2. Valiktor — декларативная валидация с fluent API

Valiktor предлагает интуитивно понятный DSL для описания правил. Библиотека поддерживает вложенные объекты, коллекции и кастомные сообщения об ошибках. Это один из самых популярных инструментов для Kotlin.

Установка

// build.gradle.kts
dependencies {
    implementation("org.valiktor:valiktor-core:0.12.0")
}

Пример с вложенными объектами

import org.valiktor.*
import org.valiktor.functions.*

data class Address(val city: String, val zip: String)
data class Person(val name: String, val email: String, val address: Address)

fun validatePerson(person: Person) {
    validate(person) {
        validate(Person::name).isNotBlank().hasSize(min = 2, max = 50)
        validate(Person::email).isEmail()
        validate(Person::address) {
            validate(Address::city).isNotBlank()
            validate(Address::zip).matches("\\d{5}".toRegex())
        }
    }
}

fun main() {
    val person = Person("", "invalid-email", Address("", "123"))
    try {
        validatePerson(person)
    } catch (e: ConstraintViolationException) {
        e.constraintViolations.forEach { violation ->
            println("${violation.property}: ${violation.message}")
        }
    }
}

Особенности Valiktor:

  • Полная поддержка вложенных объектов и списков
  • Локализованные сообщения об ошибках
  • Интеграция с Spring Boot и Ktor

3. Kvalidation — модульная валидация на основе аннотаций

Kvalidation (ранее Koptional) предоставляет как аннотационный, так и программный подход. Библиотека особенно удобна для проверки входных данных в REST API.

Установка

// build.gradle.kts
dependencies {
    implementation("com.willowtreeapps:kvalidation:1.0.0")
}

Пример с аннотациями

import com.willowtreeapps.kvalidation.annotations.*
import com.willowtreeapps.kvalidation.Validator

data class Product(
    @field:NotBlank(message = "Product name is required")
    val name: String,

    @field:Min(0) @field:Max(10000)
    val price: Double,

    @field:Pattern(regex = "^[A-Z]{2}\\d{4}$", message = "Invalid product code")
    val code: String
)

fun main() {
    val product = Product("", -10.0, "invalid")
    val errors = Validator.validate(product)

    if (errors.isNotEmpty()) {
        errors.forEach { (field, messages) ->
            println("$field: ${messages.joinToString(", ")}")
        }
    } else {
        println("Product is valid")
    }
}

Ключевые возможности Kvalidation:

Рекомендаций