
Gestion du corps de la requête (`@RequestBody`)
Apprenez à recevoir et désérialiser les données envoyées dans le corps des requêtes HTTP (JSON, XML) en utilisant l'annotation @RequestBody dans vos contrôleurs Spring Boot.
Recevoir des données complexes : le rôle du corps de la requête
Lorsque les clients interagissent avec une API REST, ils n'envoient pas seulement des informations via l'URL (paramètres de requête, variables de chemin) ou les en-têtes. Pour des opérations comme la création (POST) ou la mise à jour (PUT, PATCH) de ressources, il est fréquent d'envoyer des données plus structurées et volumineuses directement dans le corps (body) de la requête HTTP. Ce corps contient typiquement une représentation de la ressource à créer ou à modifier, souvent au format JSON ou XML.
Spring Web MVC fournit une annotation clé pour faciliter la lecture et la conversion de ce corps de requête en objets Java manipulables dans vos méthodes de contrôleur : l'annotation @RequestBody.
@RequestBody : Lier le corps de la requête à un objet Java
L'annotation @RequestBody est placée sur un paramètre de méthode dans un contrôleur (généralement un @RestController). Elle indique à Spring que le corps de la requête HTTP entrante doit être lu et converti (désérialisé) en l'objet correspondant à ce paramètre. Cette conversion est effectuée par des composants appelés HttpMessageConverter.
Grâce à l'auto-configuration de Spring Boot, si vous avez une bibliothèque comme Jackson (pour JSON, inclus par défaut avec spring-boot-starter-web) ou JAXB (pour XML) dans votre classpath, Spring configurera automatiquement les convertisseurs appropriés. Lorsque une requête arrive avec un en-tête Content-Type indiquant, par exemple, application/json, Spring utilisera le convertisseur Jackson pour transformer le JSON du corps de la requête en une instance de la classe Java spécifiée dans le paramètre de la méthode.
Utilisation typique avec un POJO (Plain Old Java Object) :
package com.certiquizz.monappliboot.controller;
import com.certiquizz.monappliboot.dto.UserDto; // Supposons un DTO UserDto
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.*;
@RestController
@RequestMapping("/api/users")
public class UserController {
/**
* Gère les requêtes POST sur /api/users pour créer un nouvel utilisateur.
* Le corps de la requête JSON est converti en un objet UserDto.
* @param newUser Les données du nouvel utilisateur reçues dans le corps de la requête.
* @return Une réponse HTTP (201 Created) avec l'utilisateur créé.
*/
@PostMapping
public ResponseEntity createUser(@RequestBody UserDto newUser) {
System.out.println("Réception de la demande de création pour: " + newUser);
// Logique métier pour créer l'utilisateur...
UserDto createdUser = saveUserService(newUser);
// Idéalement, définir l'URI de la ressource créée dans l'en-tête Location
return ResponseEntity.status(HttpStatus.CREATED).body(createdUser);
}
// Méthode de service simulée
private UserDto saveUserService(UserDto user) {
// Simule la sauvegarde et l'attribution d'un ID
user.setId(System.currentTimeMillis()); // Exemple simple d'ID
System.out.println("Utilisateur sauvegardé: " + user);
return user;
}\n}
// Supposons une classe UserDto (à placer dans dto)
/*
package com.certiquizz.monappliboot.dto;
public class UserDto {
private Long id;
private String username;
private String email;
// Constructeurs, Getters, Setters, toString...
// IMPORTANT: Un constructeur par défaut (sans argument) et/ou
// des setters sont souvent nécessaires pour la désérialisation par Jackson.
public UserDto() {}
public Long getId() { return id; }
public void setId(Long id) { this.id = id; }
public String getUsername() { return username; }
public void setUsername(String username) { this.username = username; }
public String getEmail() { return email; }
public void setEmail(String email) { this.email = email; }
@Override public String toString() { return "UserDto{id=" + id + ", username='" + username + '\'' + ", email='" + email + '\'' + '}';}
}
*/
Dans cet exemple, lorsque le client envoie une requête POST à /api/users avec un corps JSON comme {"username":"alice", "email":"alice@example.com"} et l'en-tête Content-Type: application/json, Spring utilisera Jackson pour créer une instance de UserDto et l'injecter dans le paramètre newUser.
Types de paramètres supportés et validation
@RequestBody peut être utilisé avec différents types de paramètres :
- POJOs / DTOs : Le cas le plus courant pour les données structurées (JSON/XML). La classe doit être compatible avec le processus de désérialisation (souvent, constructeur par défaut et/ou setters).
String: Pour récupérer le corps brut de la requête sous forme de chaîne de caractères.Map: Utile pour recevoir des structures JSON flexibles ou non prédéfinies.byte[]: Pour récupérer le corps brut sous forme de tableau d'octets.- Types spécifiques : Comme
org.springframework.http.HttpEntityqui donne accès aux en-têtes et au corps.
Validation avec @Valid : Il est très fréquent d'associer @RequestBody avec l'annotation @Valid (ou @Validated) de Jakarta Bean Validation. Cela déclenche automatiquement la validation de l'objet désérialisé en fonction des contraintes (@NotNull, @Size, @Email, etc.) définies dans la classe du POJO/DTO. Si la validation échoue, Spring renvoie par défaut une erreur 400 Bad Request.
import jakarta.validation.Valid; // ou javax.validation.Valid selon la version
import jakarta.validation.constraints.Email;
import jakarta.validation.constraints.NotBlank;
import jakarta.validation.constraints.Size;
// ... dans le contrôleur ...
@PostMapping("/validated")
public ResponseEntity createValidUser(
@Valid @RequestBody ValidatedUserDto newUser) {
// Si la validation échoue, cette méthode n'est pas atteinte (erreur 400)
System.out.println("Utilisateur validé reçu: " + newUser);
// ... logique métier ...
return ResponseEntity.status(HttpStatus.CREATED).body(newUser); // Simulé
}
// ... dans la classe DTO ...
/*
package com.certiquizz.monappliboot.dto;
public class ValidatedUserDto {
private Long id;
@NotBlank(message = "Le nom d'utilisateur ne peut pas être vide")
@Size(min = 3, max = 50, message = "Le nom d'utilisateur doit contenir entre 3 et 50 caractères")
private String username;
@NotBlank(message = "L'email ne peut pas être vide")
@Email(message = "Format d'email invalide")
private String email;
// Constructeur, Getters, Setters ...
}
*/
Gestion des erreurs de désérialisation
Si le corps de la requête ne peut pas être désérialisé dans le type de paramètre attendu (par exemple, JSON mal formé, type de données incompatible), Spring lèvera généralement une exception HttpMessageNotReadableException. Par défaut, cela se traduit par une réponse HTTP avec un code de statut 400 Bad Request, indiquant que la requête du client était invalide.
Il est possible de personnaliser la gestion de ces erreurs (ainsi que les erreurs de validation) en utilisant des mécanismes comme @ControllerAdvice et @ExceptionHandler, qui permettent de retourner des messages d'erreur plus spécifiques et structurés au client.
En conclusion, l'annotation @RequestBody est indispensable pour construire des API REST qui acceptent des données complexes des clients. Couplée aux convertisseurs de messages automatiques de Spring Boot et aux capacités de validation, elle offre un moyen puissant et élégant de traiter le corps des requêtes HTTP.