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

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

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

Начать курс

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

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

Зачем нужна валидация в Kotlin?

Валидация позволяет:

  • Обеспечить целостность данных перед их обработкой;
  • Улучшить пользовательский опыт за счёт понятных сообщений об ошибках;
  • Снизить нагрузку на базу данных и серверную логику;
  • Предотвратить уязвимости, связанные с некорректным вводом.

Основные подходы к валидации

В Kotlin можно выделить три основных подхода:

  1. Аннотации — декларативный способ, часто используется с Jakarta Bean Validation (ранее JSR-380).
  2. DSL-валидация — создание валидаторов с помощью предметно-ориентированного языка (например, Konform).
  3. Функциональный подход — использование функций высшего порядка для композиции правил проверки.

1. Библиотека Konform

Konform — это лёгкая библиотека для валидации данных в Kotlin, которая использует DSL. Она идеально подходит для проверки объектов, полученных из JSON или форм.

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

import konform.*
import konform.dsl.*

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

fun main() {
    val userValidator = validation<User> {
        User::name required {
            minLength(2) hint "Имя должно содержать минимум 2 символа"
            maxLength(50) hint "Имя не должно превышать 50 символов"
        }
        User::email required {
            pattern(Regex("^[\\w.-]+@[\\w.-]+\\.\\w{2,}$")) hint "Некорректный email"
        }
        User::age required {
            range(18..120) hint "Возраст должен быть от 18 до 120 лет"
        }
    }

    val user = User("А", "invalid-email", 17)
    val result = userValidator.validate(user)
    
    if (result is ValidationResult.Invalid) {
        result.errors.forEach { (field, errors) ->
            println("Поле '$field': ${errors.joinToString(", ")}")
        }
    } else {
        println("Валидация пройдена!")
    }
}

Вывод:

Поле 'name': Имя должно содержать минимум 2 символа
Поле 'email': Некорректный email
Поле 'age': Возраст должен быть от 18 до 120 лет

2. Библиотека Kotlin Validation (KValidation)

KValidation — ещё один популярный инструмент, предоставляющий как аннотации, так и DSL. Он интегрируется с Kotlin Serialization и поддерживает вложенные объекты.

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

import io.kvalidation.annotations.*
import io.kvalidation.KValidation

@Validatable
data class Address(
    @NotEmpty(message = "Улица не может быть пустой")
    val street: String,
    
    @Range(min = 1, max = 9999, message = "Номер дома должен быть от 1 до 9999")
    val houseNumber: Int
)

@Validatable
data class Person(
    @NotEmpty(message = "Имя обязательно")
    @Length(min = 2, max = 100, message = "Имя должно содержать от 2 до 100 символов")
    val name: String,
    
    @Email(message = "Некорректный email")
    val email: String,
    
    @Valid // вложенная валидация
    val address: Address
)

fun main() {
    val person = Person("", "test", Address("", 0))
    val violations = KValidation.validate(person)
    
    violations.forEach { violation ->
        println("${violation.propertyPath}: ${violation.message}")
    }
}

3. Функциональный подход без библиотек

Если вам не нужна полноценная библиотека, можно реализовать валидацию с помощью простых функций:

data class LoginRequest(val username: String, val password: String)

sealed class ValidationError(val message: String) {
    class EmptyField(field: String) : ValidationError("Поле '$field' не может быть пустым")
    class TooShort(field: String, min: Int) : ValidationError("Поле '$field' должно содержать минимум $min символов")
}

typealias Validator<T> = (T) -> List<ValidationError>

fun <T> validate(value: T, vararg                    

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