简体   繁体   中英

Generic response for @RestController in Spring Boot?

In my Spring Boot app, I just use Optional for the first time and after examining several projects and topics, now I am trying to build an approach as shown below:


Repository:

Optional<Employee> findByEmail(String email);

Service:

public Response findByEmail(String email) {
    return employeeRepository.findByEmail(email)
            // if record is found, I think no need to return status or message
            .map(e -> Response.builder().data(e).build()) 
            .orElseGet(() -> Response.builder().status(404)
                .data(null).message("Not found!").build());
}

Response:

@Data
@Builder
public class Response {
    private int status;
    private Object data;
    private String message;
}

Controller:

@GetMapping("/employees/{email}")
public ResponseEntity<Response> findByEmail(@PathVariable String email) {
    final Response response = employeeService.findByEmail(email);
    return ResponseEntity
            .status(response.getStatus())

            .body(response.getMessage(), response.getData()); 
            // throws "Expected 1 arguments but found 2" error
}

Here is the points that I need to be clarified:

1. Is this a proper approach to use a common response for all the Optional types in a Spring Boot app? If not, how should I change it (I want to return a common response from the Service)?

2. How to fix the throws "Expected 1 arguments but found 2" error in the Controller?

From my comment above - You are mixing concerns. Service is supposed to only care about business logic (eg not HTTP Status codes). That's controller's job. Use of Optional is correct, but the Response return type from service layer is not. Also errors like Not Found are automatically handled by a Rest Controller in Spring boot if a resource is not found. If you want to add custom logic and prepare generic responses, include a proper exception handling eg @ControllerAdvice (which allows you reuse exceptions for controllers).

As an example, one of the solutions would be to throw NoSuchElementException . This is illustrative and would apply if you want to handle other such situations (eg null pointers, internal server error, authentication errors in a more custom manner) in a generic manner.

public Employee findByEmail(String email) {
    return employeeRepository.findByEmail(email) //assuming findByEmail is returning an Optional<Employee>, otherwise - simply use a null check.
            .orElseThrow(NoSuchElementException::new)
}

Inside @ControllerAdvice class

  @ExceptionHandler(NoSuchElementException.class)
  @ResponseBody
  @Order(Ordered.HIGHEST_PRECEDENCE)
  public final ResponseEntity<APIResponseErrorContainer> handleNotFound(
      NoSuchElementException ex) {
// log exception here if you wish to
    return new ResponseEntity<>(createCustomResponseBody(),  HttpStatus.NOT_FOUND);
  }

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM