Skip to content

Controlleur REST

Le décorateur @RestController

Pour une API de type REST on créera des contrôleurs en utilisant le décorateur @RestController au lieu du simple @Controller d'une application MVC.

L'avantage est que les données retournées seront autimatiquement converties au format JSON sans qu'on ait à le spécifier. Ceci rendra le traitement des données par une application web plus simple. Notez qu'avec un peu de configuration, le contrôleur peut aussi retourner les données en format XML.

Par exemple, le code suivant retournera la liste des objets récupérés au format Json.

@RestController
@RequestMapping("/api/chats")
public class ChatController {
    private final ChatService chatService;
    private final UtilisateurService utilisateurService;

    public ChatController(ChatService chatService, UtilisateurService utilisateurService) {
        this.chatService = chatService;
        this.utilisateurService = utilisateurService;
    }

    @GetMapping
    public List<Chat> findAll() {
        // Retourne la liste d'objets sérialisés au format JSON
        return chatService.findAll();
    }
}

Formatter les données retournées

  • Il est également possible de retourner des données différentes de la structure de l'objet que l'on manipule.
  • Pratique pour omettre des champes (ex: le mot de passe d'un utilisateur)
  • Pratique dans le cas où on veut exposer seulement certains attributs d'une relation.

Attention aux relations

Deux éléments en relations l'un avec l'autre peuvent provoquer facilment un cas récursif avec Hibernate. Dans les exemples utilisés ici, un chat a un propriétaire qui lui peut avoir plusieurs chats. Ainsi lorsque je récupère la liste des chats, le premier chat me retourne son objet proprio, qui lui me retourne sa liste de chats, qui eux me retournent leurs propriétaires, etc...

  • On pourra créer un DTO pour exposer les données.
  • On pourra également créer un onjet de type Request (ex: chatRequest) pour l'ajout ou modification d'éléments.

Les DTO

  • L'utilisation d'un DTO (data transfer object) nous permettra de manipuler les données avant l'envoi au client.
  • Nous permet de cibler des propriétés des relations.
  • Permet de définir la structure du JSON retourné au client.
@Getter
@Setter
@AllArgsConstructor
@NoArgsConstructor
public class ChatDTO {
    private Integer id;
    private String nom;
    private String couleur;
    private Integer age;
    private String nomProprio;
}
  • On peut utiliser cette classe pour transformer les données avant de les envoyer au client
@GetMapping("/dto")
    public List<ChatDTO> findAllDto() {
        return chatService.findAll().stream().map(
            chat -> new ChatDTO(
                chat.getId(),
                chat.getNom(),
                chat.getCouleur(),
                chat.getAge(),
                chat.getProprio() != null ? String.format("%s %s", chat.getProprio().getPrenom(), chat.getProprio().getNom()) : "Aucun propriétaire")
            ).toList();
    }
  • On peut déléguer la transformation d'un objet Chat en ChatDTO à une fonction du service approprié.
@GetMapping("/dto")
    public List<ChatDTO> findAllDto() {
        return chatService.findAll().stream().map(chat -> chatService.mapToDto(chat)).toList();
    }

Les objets Request

  • Quand on ajoute de l'information, on ne peut pas nécessairement toujours remplir tous les champs.
  • Dans l'exemple présent
    • On n'ajout pas de Id au Chat, c'est la base de données qui le fait
    • On ne peut pas associer un objet Utilisateur complet au Chat.
  • On peut créer un objet ChatRequest pour gérer la structure des données entrantes.
@Getter
@Setter
@AllArgsConstructor
@NoArgsConstructor
public class ChatRequest {
    private String nom;
    private String couleur;
    private Integer age;
    private Integer proprioId;
}
  • Donner cet objet au service qui s'occupe de créer l'objet Chat et de le sauvegarder.
// Extrait de ChatService
public Chat save(ChatRequest chatRequest) {
        Chat savedChat = new Chat();
        // Récupérer l'utilisateur pour l'associer au chat
        Utilisateur proprio = utilisateurRepository.findById(chatRequest.getProprioId());

        savedChat.setNom(chatRequest.getNom());
        savedChat.setCouleur(chatRequest.getCouleur());
        savedChat.setAge(chatRequest.getAge());
        // Associer l'objet Utilisateur au Chat
        savedChat.setProprio(proprio);

        return chatRepository.save(savedChat);
    }

Tester l'API

Postman

On peut tester les api de différentes façons. L'un des outils les plus populaires pour cela est Postman. Il faudra l'installer localement pour tester une API qui s'exécute de façon locale (localhost).

Pour tester les méthodes POST avec Postman:

  • Créer une nouvelle requête
  • Sélectionner le type POST
  • Entrer l'adresse de l'API
  • Dans la section Body
    • Choisir raw et s'assurer que l'option JSON est active
    • Inscrire les données qu'on veut envoyer au serveur au format JSON

Requête POST dans postman

cURL

  • On peut aussi tester en ligne de commande avec cURL
  • Pour une requête GET
    • curl http://localhost:8080/api/chats/dto

Résultat cURL

  • Pour une requête POST
    curl -X POST http://localhost:8080/api/chats/ajouter \
         -H "Content-Type: application/json" \
         -d '{
               "nom": "Grisou",
               "couleur": "Gris",
               "age": 3,
               "proprioId": 2
             }'
    

Requete POST cURL

  • Évidemment, le format est moins joli avec cet outil, mais il est tout aussi efficace.