Gérez les erreurs
Pour introduire la problématique, lançons dans Postman une requête GET vers http://localhost:9090/Produits/42 en indiquant l'Id d'un produit qui n'existe pas. Voici le résultat :
Étant donné que ce produit n'existe pas, cette requête ne fournit logiquement pas de réponse.
Avez-vous prêté attention au code de statut retourné ?
Malgré l'absence de réponse, la requête a fourni un code de statut 200 OK. Celui-ci indique que la requête a réussi, c'est-à-dire que le serveur a pu être appelé et n'a retourné aucune erreur particulière. Or, ce comportement peut induire en erreur ou déboussoler tout service extérieur qui viendrait utiliser notre API : il n'y a aucun résultat, mais nous indiquons quand même que tout va bien...
Pour remédier à ceci, nous allons générer une exception lorsqu'on ne trouve pas de produit :
@GetMapping(value = "/Produits/{id}")
public Product afficherUnProduit(@PathVariable int id) {
Product produit = productDao.findById(id);
if(produit==null) throw new ProduitIntrouvableException("Le produit avec l'id " + id + " est INTROUVABLE. Écran Bleu si je pouvais.");
return produit;
}
Si la variable produits est null, nous lançons une exception ProduitIntrouvableException. En effet, nous allons créer notre propre exception afin d'être le plus spécifique possible.
Dans IntelliJ, ProduitIntrouvableException devrait être rouge car il n'y a pas de classe de ce nom. Cliquez sur ProduitIntrouvableException et une lampe rouge s'affiche à gauche, vous proposant de créer cette exception automatiquement.
Cliquez dessus : une nouvelle fenêtre s'ouvre et vous propose de choisir un package dans lequel placer cette classe. Vous allez changer de package et en indiquer un nouveau, exceptions :
Un nouveau package est créé avec la nouvelle classe. Modifiez cette classe afin qu'elle hérite de RuntimeException. Passez ensuite le message reçu en argument via notre exception et vers la classe parent, pour qu'elle l'intègre dans l'affichage de l'erreur. Voici notre exception finale :
package com.ecommerce.microcommerce.web.exceptions;
public class ProduitIntrouvableException extends RuntimeException
{
public ProduitIntrouvableException(String s)
{
super(s);
}
}
Relancez maintenant votre requête GET sur Postman, vous obtenez donc une erreur en bonne et due forme avec notre petit message personnel :
Tout ça est bien joli , mais il y a encore quelque chose qui cloche. Est-ce que vous le voyez ? Il s'agit de l'erreur renvoyée : 500 Internal Server Error. Or, nous n'avons aucun problème de serveur, le problème est que la ressource recherchée est introuvable. Il nous faut donc retourner le code de statut adapté : 404 Not Found.
Nous allons donc modifier notre exception afin qu'elle renvoie le bon code. À cet effet, Spring fournit l'annotation @ResponseStatus qui définit le code de statut associé à l'exception. Modifiez donc votre code comme suit :
package com.ecommerce.microcommerce.web.exceptions;
import org.springframework.http.HttpStatus;
import org.springframework.web.bind.annotation.ResponseStatus;
@ResponseStatus(HttpStatus.NOT_FOUND)
public class ProduitIntrouvableException extends RuntimeException
{
public ProduitIntrouvableException(String s)
{
super(s);
}
}
L'annotation désigne le code d'erreur à renvoyer parmi la liste de tous les codes possibles. Vous pouvez d'ailleurs afficher ces codes dans IntelliJ grâce à l'assistant de code :
Redémarrez et retestez avec Postman :
Vous renvoyez ainsi un message d'erreur explicite avec le bon code HTTP.
Effectuez les validations
Jusqu'ici, lorsque nous créons un nouveau Produit grâce à la méthode ajouterProduit, nous ne vérifions à aucun moment que les données sur le produit sont correctes. Par exemple, la longueur du nom du produit doit être supérieure à 3 caractères, et le prix ne doit jamais être défini à 0 (rien n'est gratuit).
Spring propose de valider les données grâce à une dépendance spring-boot-starter-validation que je vous laisse ajouter à votre POM :
org.springframework.boot
spring-boot-starter-validation
2.6.0
Cette librairie va vous permettre de valider les données grâce à de simples annotations. Modifions la classe Product en ajoutant les annotations @Length
et @Min
, comme suit :
package com.ecommerce.micrommerce.web.model;
import javax.persistence.Entity;
import javax.persistence.Id;
import javax.validation.constraints.Min;
import javax.validation.constraints.Size;
//@JsonFilter("monFiltreDynamique")
@Entity
public class Product
{
@Id
private int id;
@Size(min = 3, max = 25)
private String nom;
@Min(value = 1)
private int prix;
…
}
Explications :
@Size : accepte en argument un minimum et un maximum, et vérifie donc si la longueur de la chaîne est conforme.
@Min : définit la valeur minimale.
Il nous faut également indiquer dans notre contrôleur que le produit reçu de l'utilisateur est à valider. Pour ce faire, il faut ajouter l'annotation @Valid
, comme illustré ci-après :
public ResponseEntity<Void> ajouterProduit(@Valid @RequestBody Product product)
{
....
}
Lancez un POST depuis Postman pour tester :
Vous voyez le bon code d'erreur : 400 Bad Request.
En résumé
Nous savons générer nos entités avec
@Valid
.
Nous allons maintenant documenter notre API avec Swagger. Allons-y !