Search code examples
javaspringrestspring-mvcspring-restcontroller

Spring Rest Controller: Correct way to return entities from mapping methods?


I have the following Rest Controller class that handles HTTP requests relating to my Client entity?

For context - a client (e.g. exercise client) can have one Trainer. But a Trainer can have many clients.

Am I returning the entities in the correct way from my controller? I am using the Spring ResponseEntity class to wrap the Client related responses.Is there any other controller implementations I am missing in order to improve this code? - i.e.

Controller:

@RestController
@RequestMapping(value = "/clients")
public class ClientController {

    private final ClientService clientService;

    public ClientController(ClientService clientService) {
        this.clientService = clientService;
    }

    @GetMapping("/{clientId}")
    ResponseEntity<Client> getClientById(@PathVariable long clientId) {
        Client Client = clientService.getClientById(clientId);
        return new ResponseEntity<>(Client, HttpStatus.OK);
    }

    @GetMapping("/trainer/{trainerId}")
    ResponseEntity<List<Client>> getClientsByTrainerId(@PathVariable long trainerId) {
        List<Client> clients = clientService.getClientsByTrainerId(trainerId);
        return new ResponseEntity<>(clients, HttpStatus.OK);
    }

    @PostMapping
    public ResponseEntity<Client> createClient(@RequestBody ClientDTO clientDTO) {
        Client newClient = clientService.createNewClient(clientDTO);
        return new ResponseEntity<>(newClient, HttpStatus.CREATED);
    }

    @PutMapping("/{clientId}")
    ResponseEntity<Client> updateClient(@PathVariable Long clientId, @RequestBody ClientDTO clientDTO) {
        Client editedClient = clientService.editClient(clientId, clientDTO);
        return new ResponseEntity<>(editedClient, HttpStatus.OK);
    }

}

Edit: Add Delete method

@DeleteMapping("/{clientId}")
long deleteClient(@PathVariable long clientId) {
    clientService.deleteClient(clientId);
    return clientId;
}

Solution

  • There's no need in the code above for the return types to be ResponseEntity<>. You can declare controller methods to return any type of object, and Spring is smart enough to wrap your intended return type in a ResponseEntity as needed.

    For example:

        @GetMapping("/{clientId}")
       Client getClientById(@PathVariable long clientId) {
            return clientService.getClientById(clientId);
       }
    

    If you want to return a different HTTP status code besides 200 OK, you can use an annotation for that. For example:

        @PostMapping
        @ResponseStatus(HttpStatus.CREATED)
        public Client createClient(@RequestBody ClientDTO clientDTO) {
            return clientService.createNewClient(clientDTO);
        }
    

    The only time I ever make controller methods return ResponseEntitiy<> is if I have logic in the method that returns different response types (status codes) based on some conditions.


    As an aside, it's usually not a good idea to return your entities directly in API endpoints. Most of the time you're going to want to transform the entity types into DTO types, to separate the public representation of things from the persistent representations. The DTO can have whatever shape you want to expose to clients, and can vary independently from the domain or persistent form. At first this might seem like unnecessary form of code duplication; sometimes the two never diverge or have differing structure, names, etc. But many times experience has taught us that the domain/persistent entities evolve differenty from the API contract.