Giuliopime
09/27/2022, 7:46 AMfun Application.configureValidator() {
install(RequestValidation) {
validate<ClientUserDto> {
val validationResult = it.validate(it)
if (validationResult is Valid)
ValidationResult.Valid
else
ValidationResult.Invalid(
validationResult.errors.map { error -> "${error.dataPath} ${error.message}" }
)
}
validate<ClientListDto> {
val validationResult = it.validate(it)
if (validationResult is Valid)
ValidationResult.Valid
else
ValidationResult.Invalid(
validationResult.errors.map { error -> "${error.dataPath} ${error.message}" }
)
}
validate<ClientListItemDto> {
val validationResult = it.validate(it)
if (validationResult is Valid)
ValidationResult.Valid
else
ValidationResult.Invalid(
validationResult.errors.map { error -> "${error.dataPath} ${error.message}" }
)
}
}
}
Roukanken
09/27/2022, 8:35 AMvalidate
methods are from some interfaceRoukanken
09/27/2022, 8:39 AMdata class ValidationErrorReason(val dataPath: String, val message: String)
sealed interface MyValidationResult {
object Valid : MyValidationResult
data class Invalid(val errors: List<ValidationErrorReason>) : MyValidationResult
}
interface Validatable<T> {
fun validate(arg: T): MyValidationResult
}
data class ClientUserDto(val name: String) : Validatable<ClientUserDto> {
override fun validate(arg: ClientUserDto) = TODO()
}
data class ClientListDto(val name: String) : Validatable<ClientListDto> {
override fun validate(arg: ClientListDto) = TODO()
}
data class ClientListItemDto(val name: String) : Validatable<ClientListItemDto> {
override fun validate(arg: ClientListItemDto) = TODO()
}
special attention to the interface:
interface Validatable<T> {
fun validate(arg: T): MyValidationResult
}
now you can write a function:
inline fun <reified T : Validatable<T>> RequestValidationConfig.validateValidatable() =
validate<T> {
val validationResult = it.validate(it)
if (validationResult is MyValidationResult.Invalid)
ValidationResult.Invalid(
validationResult.errors.map { error -> "${error.dataPath} ${error.message}" }
)
else
ValidationResult.Valid
}
(I reversed the if, as kotlin did not want to infer that errors
exists for some reason)
and then you write:
install(RequestValidation) {
validateValidatable<ClientUserDto>()
validateValidatable<ClientListDto>()
validateValidatable<ClientListItemDto>()
}
in your configureValidator
functionRoukanken
09/27/2022, 8:44 AMinstall(RequestValidation)
requires a lambda of type RequestValidationConfig.() -> Unit
We can take advantage of that receiver so we can call validate
on it and write
fun RequestValidationConfig.validateValidatable() =
validate<...> { }
and since you want to do it for various types, you need reified generics (as validate
needs them) and you bind them to some type so you can call your method it.validate(it)
Roukanken
09/27/2022, 8:45 AMit.validate(it)
method? Shouldn't it be just it.validate()
?Giuliopime
09/27/2022, 8:56 AM