blue-sky
blue-sky

Reputation: 53876

What to return if item is not present?

Given this code:

@GetMapping("/data/{id}")
public Data retrieveDataById(@PathVariable Long id) {

    Optional<Data> data = dataService.findById(id);

    if(data.isEmpty()){
        return null;
    }
    else {
        return data.get();
    }

}

The primary issue I think is that null is being returned if the item is not found.

So, instead of

    if(data.isEmpty()){
        return null;
    }

I plan to change it to:

    if(data.isEmpty()){
        ResponseEntity.ok("No records found for id"+id);
    }

Is this correct or are there other changes I should consider ?

Update:

The change results in the return type changing from Data to ResponseEntity. Should I add data.get(); onto the ResponseEntity if the data is present ? Changing

Upvotes: 2

Views: 2569

Answers (4)

Ludi
Ludi

Reputation: 463

if you do not want to use the ResponseEntity you can also throw a ResponseStatusException as shown here: https://www.baeldung.com/spring-response-status-exception#1-generate-responsestatusexception

Upvotes: 2

Andrew Kolesnyk
Andrew Kolesnyk

Reputation: 211

Optional gives you ability to do some operations with its value in a stream-like way. If you develop rest endpoints in Spring you could either return ResponseEntity as Joop Eggen mentioned or you could create @ControllerAdivce and throw exception that it would catch and send a proper http status. In terms of scalability, the second approach is better, because you can use it with various controllers.

So the first case:

@GetMapping("/data/{id}")
public ResponseEntityy<?> retrieveDataById(@PathVariable Long id) {
    return dataService.findById(id)
             .map(value -> new ResponseEntity<>(value, HttpStatus.OK))
             .orElse(ResponseEntity.notFound().build());
}

The second case:

@GetMapping("/data/{id}")
public Data retrieveDataById(@PathVariable Long id) {
    return dataService.findById(id).orElseThrow(() -> new YourCustomRuntimeException());
}

@ControllerAdvice
class ControllerExceptionHandler {
    @ResponseStatus(HttpStatus.NOT_FOUND) 
    @ExceptionHandler(YourCustomRuntimeException.class)
    public ResponseEntity elementNotFound() {
        return ResponseEntity.notFound().build();
    }
}

Upvotes: 3

WMG
WMG

Reputation: 336

It would be better to wrap the response when returning from Controllers

@GetMapping("/{id}")
    public ResponseEntity<RoleDto> findById(@PathVariable String id) {
        return ResponseEntity.ok(roleService.findById(id));
    }

For the service layer, returning custom exception with a related error message would be more flexible when dealing with the situation later.

public RoleDto findById(String id) {
        Optional<Role> role = roleRepository.findById(id);
        return role.map(roleMapper::toDto).orElseThrow(() -> new ResourceNotFoundException(id, "Role not found"));
    }

Custom exception can be treated according to end-user requirement by implementing @ControllerAdvice, Controller level @ExceptionHandler or ResponseStatusException from Spring 5

The change results in the return type changing from Data to ResponseEntity. Should I add data.get(); onto the ResponseEntity if the data is present ? Changing

Yes, you can. Normally you can do this operation in the service layer and return DTO to the relevant controller.

Upvotes: 4

Ananthapadmanabhan
Ananthapadmanabhan

Reputation: 6216

You could change it to like :

@GetMapping("/data/{id}")
public Data retrieveDataById(@PathVariable Long id) {

    Optional<Data> data = dataService.findById(id);

    if(data.isEmpty()){
        return new ResponseEntity("No records found for id"+id , HttpStatus.NOT_FOUND);
    }
    else {
        return data.get();
    }

}

Change the HttpStatus Code to 404 which indicates NOT FOUND instead of returning 200 as the status code for this scenario.

Upvotes: 1

Related Questions