KValid — integraciones¶
Las integraciones son módulos opcionales: el core nunca depende de un framework. Ambas
traducen una ValidationException (lanzada por getOrThrow() sobre un ValidationResult) a un
400 con el cuerpo de errores.
Ejemplos ejecutables y verificados en kvalid-samples
(AppKtor.kt con test end-to-end, AppSpring.kt).
Ktor (kvalid-ktor)¶
dependencies {
implementation("io.github.kuroxbyte:kvalid-ktor:0.4.0")
}
StatusPages { kvalid() } registra el manejo de ValidationException:
fun Application.kvalidModule() {
install(ContentNegotiation) { json() }
install(StatusPages) { kvalid() } // ← integración
routing {
post("/users") {
val req = call.receive<UserRequest>()
val user = User(req.name, req.age, req.email).validate().getOrThrow()
call.respond(mapOf("created" to user.name))
}
}
}
Un request inválido responde 400 con ValidationErrorResponse(errors = [...]); uno válido,
200. El status es configurable: kvalid(status = HttpStatusCode.UnprocessableEntity).
Spring (kvalid-spring)¶
dependencies {
implementation("io.github.kuroxbyte:kvalid-spring:0.4.0")
}
KValidExceptionHandler es un @RestControllerAdvice que convierte la ValidationException en
un ResponseEntity 400. Regístralo como bean (component-scan o @Import):
@RestController
open class UserController {
@PostMapping("/users")
open fun create(@RequestBody req: UserRequest): Map<String, String> {
val user = User(req.name, req.age, req.email).validate().getOrThrow()
return mapOf("created" to user.name)
}
}
// + registrar KValidExceptionHandler: @Import(KValidExceptionHandler::class)
i18n (kvalid-i18n)¶
Independiente del framework: resuelve code + params a texto legible. El message explícito
del constraint gana; si no, se usa la plantilla del code con interpolación de {param}.
val es = DefaultMessageResolver(mapOf(
"notBlank" to "No puede estar vacío",
"size.max" to "Máximo {max} caracteres",
"min" to "Debe ser al menos {min}",
))
user.validate().violationsOrEmpty().forEach { println(es.resolve(it)) }
En JVM, ResourceBundleMessageResolver toma las plantillas de un ResourceBundle (properties
por locale). Conéctalo dentro del handler de Ktor/Spring para respuestas ya localizadas.