I am developing a Controller in Spring Boot. In case the item is not found in the DB I would like to resurrect a ResponseEntity with Http code of type HttpStatus.NOT_FOUND, but also a message saying that the item was not found. The following method works but only returns HttpStatus.NOT_FOUND.
import org.springframework.http.ResponseEntity;
@GetMapping(
value = "/plants/{id}",
produces = MediaType.APPLICATION_JSON_VALUE
)
public ResponseEntity<?> getPlantById(@PathVariable("id") UUID id){
Optional<ResponsePlantVocDTO> responsePlantDTOOptional = service.getPlantById(id);
return responsePlantDTOOptional.map(
responsePlantVocDTO -> ResponseEntity
.status(HttpStatus.FOUND)
.body(responsePlantVocDTO))
.orElse(
ResponseEntity.notFound().build()
);
}
I have tried other solutions but I get the following error: Required type: ResponseEntity , Provided: ResponseEntity
@GetMapping(
value = "/plants/{id}",
produces = MediaType.APPLICATION_JSON_VALUE
)
public ResponseEntity<?> getPlantById(@PathVariable("id") UUID id){
Optional<ResponsePlantVocDTO> responsePlantDTOOptional = service.getPlantById(id);
return responsePlantDTOOptional.map(
responsePlantVocDTO -> ResponseEntity
.status(HttpStatus.FOUND)
.body(responsePlantVocDTO))
.orElse(
// ResponseEntity.notFound().build()
ResponseEntity.status(HttpStatus.NOT_FOUND).body("My message")
);
}
UPDATE: this is my controller
import jakarta.validation.Valid;
import orgr.plantvocdb.dto.PlantInfoDTO;
import orgr.plantvocdb.dto.RequestPlantVocDTO;
import orgr.plantvocdb.dto.ResponsePlantVocDTO;
import orgr.plantvocdb.service.PlantsVocService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.bind.annotation.*;
import java.util.List;
import java.util.Optional;
import java.util.UUID;
@RestController
@RequestMapping("/api/v1/voc")
public class PlantsVocController {
private final PlantsVocService service;
@Autowired
public PlantsVocController(PlantsVocService service) {
this.service = service;
}
/*
* GETs
* */
@GetMapping(
value = "/plants",
produces = MediaType.APPLICATION_JSON_VALUE
)
public List<PlantInfoDTO> getPlantsVocInfo(){
return service.getAllPlantsInfo();
}
/**
* Get Plant Voc by ID
*/
@GetMapping(
value = "/plants/id/{id}",
produces = MediaType.APPLICATION_JSON_VALUE
)
public ResponseEntity<?> getPlantById(@PathVariable("id") UUID id){
Optional<ResponsePlantVocDTO> optionalResponsePlantVocDTO = service.getPlantById(id);
return optionalResponsePlantVocDTO.map(
responsePlantVocDTO -> ResponseEntity
.status(HttpStatus.FOUND)
.body(responsePlantVocDTO))
.orElse(ResponseEntity.notFound().build());
}
/**
* Get Plant Voc by IPNI (International Plant Names Index) code
*/
@GetMapping(
value = "/plants/ipni/{ipni}",
produces = MediaType.APPLICATION_JSON_VALUE
)
public ResponseEntity<?> getPlantByIpni(@PathVariable("ipni") String ipni){
Optional<ResponsePlantVocDTO> optionalResponsePlantVocDTO = service.getPlantByIpni(ipni);
return optionalResponsePlantVocDTO.map(
responsePlantVocDTO -> ResponseEntity
.status(HttpStatus.FOUND)
.body(responsePlantVocDTO))
.orElse(ResponseEntity.notFound().build());
}
@GetMapping(
value = "/plants/always-emitters",
produces = MediaType.APPLICATION_JSON_VALUE
)
public List<PlantInfoDTO> getPlantsAlwaysEmitter(){
return service.getAlwaysEmitters();
}
@GetMapping(
value = "/plants/never-emitters",
produces = MediaType.APPLICATION_JSON_VALUE
)
public List<PlantInfoDTO> getPlantsNeverEmitter(){
return service.getNeverEmitters();
}
@GetMapping(
value = "/plants/mixed-emitters",
produces = MediaType.APPLICATION_JSON_VALUE
)
public List<PlantInfoDTO> getPlantsMixedEmitter(){
return service.getMixedEmitters();
}
/*
* POSTs
* */
@PostMapping(
value = "/plants",
consumes = MediaType.APPLICATION_JSON_VALUE,
produces = MediaType.APPLICATION_JSON_VALUE
)
public ResponseEntity<?> postNewPlant(
@RequestBody
@Valid
RequestPlantVocDTO plantDTO
){
System.out.println("ciao");
String name = plantDTO.getName();
ResponsePlantVocDTO newPlant = service.createPlantVoc(plantDTO);
return ResponseEntity
.status(HttpStatus.CREATED)
.body(newPlant);
}
}
I am developing a Controller in Spring Boot. In case the item is not found in the DB I would like to resurrect a ResponseEntity with Http code of type HttpStatus.NOT_FOUND, but also a message saying that the item was not found. The following method works but only returns HttpStatus.NOT_FOUND.
import org.springframework.http.ResponseEntity;
@GetMapping(
value = "/plants/{id}",
produces = MediaType.APPLICATION_JSON_VALUE
)
public ResponseEntity<?> getPlantById(@PathVariable("id") UUID id){
Optional<ResponsePlantVocDTO> responsePlantDTOOptional = service.getPlantById(id);
return responsePlantDTOOptional.map(
responsePlantVocDTO -> ResponseEntity
.status(HttpStatus.FOUND)
.body(responsePlantVocDTO))
.orElse(
ResponseEntity.notFound().build()
);
}
I have tried other solutions but I get the following error: Required type: ResponseEntity , Provided: ResponseEntity
@GetMapping(
value = "/plants/{id}",
produces = MediaType.APPLICATION_JSON_VALUE
)
public ResponseEntity<?> getPlantById(@PathVariable("id") UUID id){
Optional<ResponsePlantVocDTO> responsePlantDTOOptional = service.getPlantById(id);
return responsePlantDTOOptional.map(
responsePlantVocDTO -> ResponseEntity
.status(HttpStatus.FOUND)
.body(responsePlantVocDTO))
.orElse(
// ResponseEntity.notFound().build()
ResponseEntity.status(HttpStatus.NOT_FOUND).body("My message")
);
}
UPDATE: this is my controller
import jakarta.validation.Valid;
import org.cnr.plantvocdb.dto.PlantInfoDTO;
import org.cnr.plantvocdb.dto.RequestPlantVocDTO;
import org.cnr.plantvocdb.dto.ResponsePlantVocDTO;
import org.cnr.plantvocdb.service.PlantsVocService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.bind.annotation.*;
import java.util.List;
import java.util.Optional;
import java.util.UUID;
@RestController
@RequestMapping("/api/v1/voc")
public class PlantsVocController {
private final PlantsVocService service;
@Autowired
public PlantsVocController(PlantsVocService service) {
this.service = service;
}
/*
* GETs
* */
@GetMapping(
value = "/plants",
produces = MediaType.APPLICATION_JSON_VALUE
)
public List<PlantInfoDTO> getPlantsVocInfo(){
return service.getAllPlantsInfo();
}
/**
* Get Plant Voc by ID
*/
@GetMapping(
value = "/plants/id/{id}",
produces = MediaType.APPLICATION_JSON_VALUE
)
public ResponseEntity<?> getPlantById(@PathVariable("id") UUID id){
Optional<ResponsePlantVocDTO> optionalResponsePlantVocDTO = service.getPlantById(id);
return optionalResponsePlantVocDTO.map(
responsePlantVocDTO -> ResponseEntity
.status(HttpStatus.FOUND)
.body(responsePlantVocDTO))
.orElse(ResponseEntity.notFound().build());
}
/**
* Get Plant Voc by IPNI (International Plant Names Index) code
*/
@GetMapping(
value = "/plants/ipni/{ipni}",
produces = MediaType.APPLICATION_JSON_VALUE
)
public ResponseEntity<?> getPlantByIpni(@PathVariable("ipni") String ipni){
Optional<ResponsePlantVocDTO> optionalResponsePlantVocDTO = service.getPlantByIpni(ipni);
return optionalResponsePlantVocDTO.map(
responsePlantVocDTO -> ResponseEntity
.status(HttpStatus.FOUND)
.body(responsePlantVocDTO))
.orElse(ResponseEntity.notFound().build());
}
@GetMapping(
value = "/plants/always-emitters",
produces = MediaType.APPLICATION_JSON_VALUE
)
public List<PlantInfoDTO> getPlantsAlwaysEmitter(){
return service.getAlwaysEmitters();
}
@GetMapping(
value = "/plants/never-emitters",
produces = MediaType.APPLICATION_JSON_VALUE
)
public List<PlantInfoDTO> getPlantsNeverEmitter(){
return service.getNeverEmitters();
}
@GetMapping(
value = "/plants/mixed-emitters",
produces = MediaType.APPLICATION_JSON_VALUE
)
public List<PlantInfoDTO> getPlantsMixedEmitter(){
return service.getMixedEmitters();
}
/*
* POSTs
* */
@PostMapping(
value = "/plants",
consumes = MediaType.APPLICATION_JSON_VALUE,
produces = MediaType.APPLICATION_JSON_VALUE
)
public ResponseEntity<?> postNewPlant(
@RequestBody
@Valid
RequestPlantVocDTO plantDTO
){
System.out.println("ciao");
String name = plantDTO.getName();
ResponsePlantVocDTO newPlant = service.createPlantVoc(plantDTO);
return ResponseEntity
.status(HttpStatus.CREATED)
.body(newPlant);
}
}
Share
Improve this question
edited Feb 7 at 11:35
Gianni Spear
asked Feb 7 at 10:47
Gianni SpearGianni Spear
7,93624 gold badges91 silver badges140 bronze badges
6
|
Show 1 more comment
3 Answers
Reset to default 1I advice you not to handle errors API by API. You should throw a known exception in your system with the message, parameters and any piece of information you will judge useful. And then don't code anything in your Controller but handle it through the use of a unique @ControllerAdvice class. Thus you will have only one algorithm to return 404/400 errors to your clients and not as many as you have APIs in your code.
Please see https://www.baeldung.com/exception-handling-for-rest-with-spring#controlleradvice
The type is not the same in the Optional::map you return ResponseEntity<ResponsePlantVocDTO>
and in the orElse you return a ResponseEntity<String>
, instead you can use simple if else like this:
Optional<ResponsePlantVocDTO> optionalResponsePlantVocDTO = service.getPlantById(id);
if (optionalResponsePlantVocDTO.isPresent()) {
return ResponseEntity.status(HttpStatus.FOUND).body(optionalResponsePlantVocDTO.get());
} else {
return ResponseEntity.status(HttpStatus.NOT_FOUND).body("My message");
}
make your Controller
without the
.orElse(
// ResponseEntity.notFound().build()
ResponseEntity.status(HttpStatus.NOT_FOUND).body("My message")
);
and focus those business rules on Service. Use Throw method, you can create a business exception class
so, basically you will do:
@GetMapping(value = "/plants/id/{id}", produces = MediaType.APPLICATION_JSON_VALUE)
public ResponseEntity<ResponsePlantVocDTO> getPlantById(@PathVariable("id") UUID id){
return ResponseEntity.ok(plant);
}
public ResponseEntity<ResponsePlantVocDTO> getPlantById(UUID id) {
ResponsePlantVocDTO plant = repository.findById(id)
.orElseThrow(() -> new ResourceNotFoundException("Plant not found with id: " + id));
}
On your business exception you can create a class to make it custom:
@ResponseStatus(HttpStatus.NOT_FOUND)
public class ResourceNotFoundException extends RuntimeException {
public ResourceNotFoundException(String message) {
super(message);
}
}
Obs: its not a goot practice to transform the entity on service, you should create another level on your project for that (facade / mapper)
org.springframework.http.ResponseEntity
– Youcef LAIDANI Commented Feb 7 at 11:10