Lizard & Dog Blog

API REST Spring Boot – Partie 2

The Gist

Nous avons déjà implémenté une API Spring Boot dans la Partie 1 , et nous souhaitons y ajouter des fonctionnalités additionnelles.

Dans ce tutoriel nous implémenterons les méthodes PUT et DELETE et examinerons les autres possibilités d’accès à la base de donnée.

PUT et DELETE

La méthode PUT est une façon de traiter la transformation des données, si vous souhaitez, par exemple, mettre à jour les propriétés d’un objet existant :

Revenons à la méthode que nous avons implémentée dans la première partie :

@PutMapping("/sellAnimal")
public void sellAnimal(@RequestParam(name="name", required=true)String animalName)
{

}

Dans cette méthode, nous prendrons le nom d’un animal en tant que paramètre et mettrons à jour sa valeur sold à true.

Ensuite, nous passerons à la classe de service pour créer la méthode sous-jacente.

    public void sellAnimal(String animalName){
Animal animalToSell=animalRepository.findByName(animalName);
animalToSell.setSold(true);
animalRepository.save(animalToSell);
}

La méthode de recherche par nom n’est pas encore implémentée dans le repository, nous devons donc aller encore un peu plus loin :

@Repository
public interface AnimalRepository extends JpaRepository<Animal, Long> {
Animal findByName(String name);
}


Nous pouvons ensuite mettre à jour notre classe de contrôleur avec le code suivant :

    @PutMapping("/sellAnimal")
public void sellAnimal(@RequestParam(name="name", required=true)String animalName)
{
animalService.sellAnimal(animalName);
}

Cependant, il y a deux problèmes avec cette approche :

  1. L’animal pourrait déjà avoir été marqué comme vendu ;
  2. L’animal pourrait être absent de la liste (c’est-à-dire, un nom d’animal incorrect).

Nous devrons affiner notre méthode dans le service et le référentiel pour prendre en compte ces situations .

Dans le référentiel, nous définirons une méthode pour trouver un animal par son nom s’il n’a pas encore été vendu :

@Repository
public interface AnimalRepository extends JpaRepository<Animal, Long> {
Animal findByName(String name);
Animal findByNameAndSoldFalse(String name);
}

Pour informer l’utilisateur des problèmes potentiels liés à la vente, nous inclurons un message informatif si l’animal est déjà vendu ou s’il n’existe pas dans la base de données. Nous modifions donc notre classe de service :

public String sellAnimal(String animalName){

Animal animalToSell=animalRepository.findByNameAndSoldFalse(animalName);
if(animalToSell!=null){
animalToSell.setSold(true);
animalRepository.save(animalToSell);
return 'Animal sold!';
}
else {
return "Animal doesn't exist or has already been sold";
}
}

Nous allons également modifier la fonction de notre contrôleur pour renvoyer une chaîne de caractères qui devrait être affichée à l’utilisateur pour indiquer si la transaction a réussi. Notre méthode finale est donc la suivante :

@PutMapping("/sellAnimal")
public String sellAnimal(@RequestParam(name="name", required=true)String animalName)
{
return animalService.sellAnimal(animalName);
}

Passons à l’opération DELETE. Dans le cas de notre projet, la fonction de suppression sera utilisée si un animal a été donné plutôt que vendu. Il est ensuite supprimé de la base de données. Nous commençons par interroger le référentiel par ID. Cela renvoie une valeur optionnelle. De même que pour la méthode PUT, nous vérifierons d’abord si l’animal est présent avant toute opération ultérieure, afin d’éviter les erreurs.

public String removeAnimal(Long animalID){
Optional<Animal> animalToRemove=animalRepository.findById(animalID);
if(animalToRemove.get()!=null){
animalRepository.delete(animalToRemove.get());
return "Animal donated!";
}
else {
return "Animal doesn't exist or has already been sold";
}
}

Nous utilisons les mêmes vérifications de cohérence que dans le premier cas, mais cette fois-ci, nous supprimons directement l’animal de la base de données et informons l’utilisateur avec une chaîne de caractères indiquant le succès de la transaction.

Nous pouvons ensuite mettre à jour notre contrôleur comme suit :

@DeleteMapping("/removeAnimalFromInventory")
public String removeAnimal(@RequestParam(name="id", required=true)long animalID)
{
return animalService.removeAnimal(animalID);
}

Nous avons donc vu les méthodes POST, GET , PUT et DELETE. Nous verrons ensuite d’autres opérations réalisables sur la base de données.

Opérations supplémentaires sur la base de données

Requêtes complexes

Vous avez peut-être remarqué que lorsque nous utilisons les méthodes définies dans le repository, elles se traduisent directement en instructions psql qui sont interprétées directement sur la base de données.

Cependant, si vous souhaitez gérer des requêtes plus complexes, vous devrez utiliser l’annotation @Query dans le repository. Pour illustrer cela, nous allons définir une requête où l’utilisateur souhaite lister les trois premiers chats invendus par ordre de prix :

@Repository
public interface AnimalRepository extends JpaRepository<Animal, Long> {
// The rest of your repository code goes here
Query("SELECT a FROM Animal a WHERE a.species = 'cat' AND a.isSold = false ORDER BY a.price LIMIT 3")
List<Animal> findFirstThreeUnsoldCats();
}

À l’intérieur de l’annotation @Query, vous remarquerez une expression qui n’est pas trop différente d’une requête PSQL classique, qui serait dans ce cas :

SELECT * FROM animals WHERE species = 'cat' AND sold = false ORDER BY id LIMIT 3;

Vous pouvez utiliser l’annotation @Query en conjonction avec l’annotation @Modifying pour définir des méthodes sur le repository qui effectuent une mise à jour (UPDATE) ou une suppression (DELETE) d’une ligne :

@Repository
public interface AnimalRepository extends JpaRepository<Animal, Long> {
// The rest of your repository code goes here
@Modifying
@Query("UPDATE Animal a SET a.sold = true WHERE a.species = 'cat' AND a.sold = false ORDER BY a.id")
void updateFirstThreeUnsoldCats();}

Un petit exercice : implémentez une requête de suppression (DELETE) qui supprime les animaux au lieu de les mettre à jour.

Pagination

Spring Boot permet également de renvoyer le contenu sous forme de “Pages”, ce qui est une bonne façon d’organiser vos données si elles sont destinées à être lues sur un site web, par exemple. Pour ce faire, implémentez la ligne suivante dans votre repository :

Page<Animal> findAll(Pageable pageable);

Dans le service:

    public Page<Animal> findAllPaged(Pageable pageable) {
return animalRepository.findAll(pageable);
}

Et dans le Controller:

@GetMapping("/paged")
public Page<Animal> getAnimalsPaged(
@RequestParam(defaultValue = "0") int page,
@RequestParam(defaultValue = "10") int size) {
PageRequest pageable = PageRequest.of(page, size);
return animalService.findAllPaged(pageable);
}

Cela vous permet d’afficher tous les animaux par pages. Pour les afficher, vous passeriez le numéro de page et la taille de la page en tant que paramètres, et cela renverrait essentiellement une liste de la taille spécifique des éléments choisis.

Headers vs Params

Jusqu’à présent, nous avons utilisé des paramètres pour nos requêtes. Spring permet également de spécifier des en-têtes (headers) pour une requête. Voici les principales différences entre les paramètres et les en-têtes :

Headers :

  1. Emplacement : Les en-têtes font partie de la requête HTTP et de la réponse. Ils contiennent des métadonnées ou des informations supplémentaires sur la requête ou la réponse.
  2. Objectif : Les en-têtes transportent des informations telles que le type de contenu, l’encodage, les jetons d’authentification et d’autres métadonnées qui ne sont pas directement liées au contenu de la requête ou de la réponse.
  3. Utilisation : Les en-têtes sont souvent utilisés pour contrôler le comportement de la requête ou transmettre des informations qui s’appliquent à l’ensemble de la requête ou de la réponse.

Paramètres :

  1. Emplacement : Les paramètres font partie de l’URL dans le cas des paramètres de requête (dans la chaîne de requête) ou font partie du corps de la requête dans le cas des paramètres de formulaire ou des charges utiles JSON.
  2. Objectif : Les paramètres fournissent des données d’entrée au serveur. Ils sont utilisés pour envoyer des informations liées à l’opération spécifique ou à la ressource qui est accédée.
  3. Utilisation : Les paramètres sont couramment utilisés dans les points d’API, les soumissions de formulaires et le routage dynamique des URL. Ils contribuent à personnaliser le comportement d’une requête spécifique.

Pour travailler avec les headers au lieu des paramètres, vous pouvez le faire de la manière suivante (ici dans le cas de la méthode buyAnimal) :

@PostMapping("/buyAnimal")
public void buyAnimal(@RequestHeader(name="name", required=true)String name,
@RequestHeader(name="species", required=true)String species,
@RequestHeader(name="price", required=true) double price )
{
animalService.buyAnimal(name, species, price);
}

Conclusion et prochaines étapes:

Ce tutoriel devrait vous aider à démarrer avec le développement d’API REST Spring Boot. Une bonne prochaine étape serait de vous pencher sur Spring Security, qui est un framework ajoutant une couche de sécurité à vos applications.

Si vous avez d’autres questions, n’hésitez pas à nous les poser à :

www.lizardanddog.com

https://www.cloco.ai

Leave a comment