Obtenga el cuerpo HTTP POST en Spring Boot con @RequestBody

En este artículo, veremos cómo obtener el cuerpo HTTP POST en Spring usando la anotación @RequestBody y deserializar su contenido JSON en un POJO para su procesamiento.

Introducción

Con Spring, asignamos solicitudes a controladores de solicitudes a través de la anotación @RequestMapping. Spring Boot nos presentó los tipos derivados de esta anotación: @GetMapping, @PostMapping, @DeleteMapping, etc.

Estas solicitudes contienen diferentes tipos de información y datos, y dependiendo de lo que haga nuestro punto final con la solicitud, es posible que queramos recuperar el cuerpo de una solicitud “POST” para registrarla o procesarla más.

La anotación @RequestBody nos permite recuperar el cuerpo de la solicitud. Luego podemos devolverlo como una cadena o deserializarlo en un Plain Old Java Object (POJO).

Spring tiene mecanismos incorporados para deserializar objetos JSON y XML en POJO, lo que también facilita mucho esta tarea.

En este artículo, obtendremos el cuerpo de una solicitud HTTP POST y lo empaquetaremos en una cadena, así como también lo deserializaremos en un POJO.

Obtener el cuerpo HTTP POST como una cadena

Comencemos con una clase @Controller para manejar una solicitud entrante:

1
2
3
4
@ResponseBody
@Controller
@RequestMapping("/response")
public class HomeController {}

Lo que vale la pena señalar aquí es que hemos agregado la anotación @ResponseBody al @Controller. De esta manera, no representará una plantilla como cuerpo de respuesta, sino que devolverá un cuerpo de respuesta. Específicamente, lo empaquetaremos en un String y lo devolveremos.

Spring Boot nos presentó otro tipo derivado: @RestController, que es solo una combinación de las dos anotaciones anteriores. Usemos eso en su lugar por brevedad:

1
2
3
@RestController
@RequestMapping("/response")
public class HomeController {}

Ahora, avancemos y definamos un controlador de solicitudes. Dado que estamos manejando una solicitud POST, usaremos la anotación @PostMapping para ello:

1
2
3
4
5
6
7
8
9
@RestController
@RequestMapping("/response")
public class HomeController {

    @PostMapping("/postbody")
    public String postBody(@RequestBody String fullName) {
        return "Hello " + fullName;
    }
}

Para recuperar el cuerpo de la solicitud POST enviada al controlador, usaremos la anotación @RequestBody y asignaremos su valor a una cadena. Esto toma el cuerpo de la solicitud y lo empaqueta ordenadamente en nuestra cadena fullName. A continuación, hemos devuelto este nombre, con un mensaje de saludo.

Probemos este controlador a través de curl:

1
curl -X POST -H "Content-type: application/json" -d "John Smith" "http://localhost:8080/response/postbody"

Esto resulta en:

1
Hello John Smith

Deserializar HTTP POST en POJO

Ahora, por lo general, no trabajaremos con cadenas, aunque sirven como un buen ejemplo para el aprendizaje. En la mayoría de los casos, querremos realizar algún procesamiento o, al menos, serializar la solicitud en un POJO. Definamos un POJO de Persona con firstName y lastName:

1
2
3
4
5
6
public class Person {
    private String firstName;
    private String lastName;
    
    // Constructor, getters and setters
}

Realizaremos el mismo proceso que en el ejemplo anterior, con el mismo controlador. Sin embargo, esta vez, especificaremos que el controlador acepta valores JSON y XML y que genera respuestas JSON o XML.

Recuperaremos un cuerpo de solicitud POST en formato JSON, lo deserializaremos en un POJO para su posterior procesamiento (guardar en una base de datos, por ejemplo) y devolveremos una respuesta JSON.

Aunque Spring Boot puede hacer coincidir automáticamente el cuerpo JSON con nuestro POJO, dado que los nombres de las variables coinciden, estableceremos explícitamente esta opción. Estableceremos los formatos de entrada y salida usando las banderas consume y produce en @PostMapping:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
@RestController
@RequestMapping("/response")
public class HomeController {

     @PostMapping(
        value = "/postbody",
        consumes = {MediaType.APPLICATION_JSON_VALUE, MediaType.APPLICATION_XML_VALUE},
        produces = {MediaType.APPLICATION_JSON_VALUE, MediaType.APPLICATION_XML_VALUE})
    public ResponseEntity<Person> postBody(@RequestBody Person person) {
        Person persistedPerson = personService.save(person);
        return ResponseEntity
            .created(URI
                     .create(String.format("/persons/%s", person.getFirstName())))
            .body(persistedPerson);
    }
}

Aquí, estamos aceptando JSON y XML, además de producirlo de nuevo. Hemos anotado la instancia Person como @RequestBody, que también estaremos esperando de la solicitud. Luego, usamos una instancia PersonService para guardar a la persona en una base de datos, que también devuelve el objeto persistente para su posterior procesamiento.

En aras de la brevedad, hemos omitido la implementación PersonService ya que es una implementación estándar de la capa de servicio.

Finalmente, hemos devuelto un objeto ResponseEntity. Es solo una extensión de la clase HttpEntity que también tiene un código de estado. Hemos establecido el código de estado como CREADO con una ubicación URI donde se encuentra el nuevo recurso creado. Luego, configuramos el cuerpo de ResponseEntity como la instancia de persistentPerson y construimos la respuesta.

Probemos este controlador a través de curl nuevamente:

1
curl -X POST -H "Content-type: application/json" -d "{\"firstName\" : \"John\", \"lastName\" : \"Smith\"}" "http://localhost:8080/response/postbody"

Aquí, hemos realizado una solicitud POST con un cuerpo JSON, que contiene el nombre y apellido de una persona y la enviamos a nuestro punto final. Jackson inicia el proceso de deserialización y asigna el JSON entrante a nuestro POJO:

json to pojo mapping

El endpoint, después de guardar la entidad Person, responde con:

1
{"firstName":"John","lastName":"Smith"}

Conclusión

En este tutorial, hemos cubierto dos formas de capturar el cuerpo de una solicitud HTTP POST en un controlador Spring Boot.

Usando la anotación @RequestBody, asignamos el cuerpo a una cadena y lo devolvimos. Luego, definimos un POJO para deserializar el contenido JSON entrante, lo procesamos y finalmente devolvimos una ResponseEntity.