Ahorra tiempo en el procesamiento de las requests (body) en Spring Boot (Kotlin)
09-10-2025
Actualmente en el equipo estamos introduciendo Kotlin en un proyecto de REST API de Java con Spring Boot. Durante este proceso, he notado que el manejo de la serialización y validación de datos en los controladores es mucho más explícito, lo que resulta ideal para el paradigma funcional. Como la “frontera” de nuestra API, los controladores se vuelven responsables de validar los datos externos antes de que entren en el dominio de nuestra aplicación. Este artículo es un resumen de lo que he aprendido y que te será de gran utilidad para agilizar el desarrollo con un serializado y validación automática, de manera sencilla y declarativa.
1. Data Class: El Reemplazo Natural de los Java Records
En Java, usamos record
para crear clases inmutables que solo contienen datos. En Kotlin, el equivalente es la data class
. Con solo unas pocas líneas de código, en ambos, el compilador genera automáticamente los métodos equals()
, hashCode()
, toString()
y copy()
, perfectos para la tarea de un DTO.
La mayor diferencia y una gran ventaja es la seguridad de tipos y la nulabilidad (en este artículo traté este tema en detalle). En Kotlin, una variable no puede ser null
a menos que lo indiques explícitamente con un signo de interrogación (?
). Esto evita errores de deserialización y NullPointerException
al procesar JSON.
-
val name: String
→ No puede ser nula. -
val name: String?
→ Puede ser nula.
Para más información: Consulta la documentación oficial de Kotlin sobre data class.
2. Mapeo de JSON: Cuando el Nombre es Diferente
A veces, el nombre de los campos en el JSON que recibes no coincide con la convención camelCase
que usamos en Kotlin (por ejemplo, si usa snake_case
). Para resolver esto, usamos la anotación @JsonProperty
de la librería Jackson, que Spring usa por defecto para el mapeo.
Ejemplo:
data class Data( @JsonProperty("some_data") val someData: Double, @JsonProperty("other_data") val otherData: Double )
Para más información: Revisa este artículo JsonIgnore, JsonProperty y JsonAlias – Acceso a datos con Quarkus – makigas.
3. @param
vs. @field
: El Secreto Detrás de las Anotaciones
Para que la anotación se aplique correctamente, a veces necesitamos especificar el use-site target . La diferencia radica en a qué parte del código se aplica la anotación:
@param:
se aplica al parámetro del constructor . Es la forma preferida para propiedades inmutables (val
), ya que garantiza que el valor se asigna solo durante la creación del objeto.
data class UserProfile(@param:JsonProperty("user_name") val userName: String)
En este caso, @param:JsonProperty
le indica a Jackson que use el constructor para mapear el campo user_name
del JSON a la propiedad userName
.
@field:
se aplica al campo subyacente que Kotlin crea internamente. Esto es menos común para DTOs y puede romper la inmutabilidad deval
, ya que le permite a la librería inyectar el valor directamente.
data class UserProfile(@field:JsonProperty("user_name") val userName: String)
Aquí, Jackson intenta acceder y modificar el campo directamente, lo cual es menos seguro con propiedades inmutables.
Para más información: Consulta la documentación oficial de Kotlin sobre los targets de anotaciones.
4. Validación Automática y Robusta
Spring Boot tiene la capacidad de validar los DTOs de forma declarativa usando anotaciones del estándar Jakarta Bean Validation .
Aquí están las piezas clave:
-
Anotaciones en el DTO : Usas anotaciones como
@DecimalMin("0.0")
y@DecimalMax("100.0")
para definir las reglas en las propiedades. -
@Valid
en el Controlador : En tu método de controlador, colocas la anotación@Valid
junto a@RequestBody
. Esto le indica a Spring que debe validar el DTO antes de ejecutar tu código.
import jakarta.validation.Valid import org.springframework.web.bind.annotation.PostMapping import org.springframework.web.bind.annotation.RequestBody import org.springframework.web.bind.annotation.RestController import org.springframework.http.ResponseEntity @RestController class DataController { @PostMapping("/some") fun saveData(@Valid @RequestBody data: Data): ResponseEntity<String> { // Tu código de negocio aquí. ¡Sabes que los datos son válidos! return ResponseEntity.ok("Data received and validated successfully!") } }
Para más información: Revisa la guía de Java Bean Validation de la documentación.
5. El Flujo de la Validación: Del Request al Bad Request
El proceso de validación es un “middleware” que intercepta la petición antes de que llegue a tu método.
-
Petición HTTP : Un cliente envía la petición con un cuerpo JSON.
-
Spring Boot : Recibe la petición y la dirige a tu controlador.
-
Anotaciones : Spring detecta
@RequestBody
y@Valid
. -
Validación : Si el JSON no cumple con las reglas, el Validator lanza una
MethodArgumentNotValidException
. -
Manejo de Excepciones : Spring Boot tiene un manejador por defecto que atrapa esta excepción y genera una respuesta
HTTP 400 Bad Request
, informando al cliente sobre el error.
Tu método de controlador solo se ejecutará si los datos son válidos, lo que mantiene tu lógica de negocio limpia y libre de validaciones manuales.
Para tener un detalle de cómo es de una manera visual puedes ver el siguiente diagrama de secuencia:
Conclusiones
Al introducir Kotlin he visto que es necesario entender mejor cómo funciona la magia de Spring Boot para poder usar correctamente las data class de Kotlin. Además, adoptando la perspectiva no defensiva interna en el sistema, es decir, validando en la frontera, Java Bean Validation permite hacer esto de manera muy sencilla y declarativa ahorrando tiempo de desarrollo y tests que mantener a la par que se asegura un diseño más simple.