¿Cuál es la mejor manera de devolver diferentes tipos de ResponseEntity en Spring-Boot (Manejo de errores para REST con Spring)

7 minutos de lectura

Avatar de usuario de Saveendra Ekanayake
Saveendra Ekanayake

He escrito una aplicación REST simple en Spring Boot (Spring Estructura).

Vuelve ResponseEntity<Success> como Éxito respuesta en el nivel del controlador. Pero quiero volver de una manera completamente diferente. Error respuesta ResponseEntity<Error>si hay un error (error de validación, error de lógica, error de tiempo de ejecución) en la API.

Éxito & Error las respuestas son completamente diferentes para la aplicación.
Success & Error son las 2 clases java que la aplicación utiliza para representar Éxito & Error respuestas

¿Cuál es la mejor manera de devolver diferentes tipos de ResponseEntity en Spring-Boot (La mejor manera de manejar los errores para REST con Spring)?

  • Una solución es usar ResponseEntity<Object>. Otra es usar una BaseClass o Interface para los tipos Success y Error.

    – Jens

    30 de junio de 2016 a las 8:28

  • ¿No podrías simplemente regresar? ResponseEntity en tu definición de método? ` public ResponseEntity myControllerMethod(…) y devuelve un ResponseEntity<Success> o un ResponseEntity<Error>

    – J. Mengelle

    30 de junio de 2016 a las 8:40

  • ResponseEntity<Either<Error, Success>> sería bueno, si pudiera implementar la estructura de datos en java

    – Ali Dehgani

    30 de junio de 2016 a las 13:08

Avatar de usuario de Mark Norman
marco normando

Recomiendo usar Spring’s @ControllerAdvice para manejar errores. Leer esta guía para una buena introducción, comenzando en la sección denominada “Manejo de errores de Spring Boot”. Para una discusión en profundidad, hay un artículo en el blog Spring.io que se actualizó en abril de 2018.

Un breve resumen de cómo funciona esto:

  • Su método de controlador solo debe devolver ResponseEntity<Success>. No será responsable de devolver respuestas de error o excepción.
  • Implementará una clase que maneje excepciones para todos los controladores. Esta clase se anotará con @ControllerAdvice
  • Esta clase de consejos de controlador contendrá métodos anotados con @ExceptionHandler
  • Cada método de manejo de excepciones se configurará para manejar uno o más tipos de excepciones. Estos métodos son donde especifica el tipo de respuesta para los errores.
  • Para su ejemplo, declararía (en la clase de consejos del controlador) un método de manejo de excepciones para el error de validación. El tipo de devolución sería ResponseEntity<Error>

Con este enfoque, solo necesita implementar el manejo de excepciones de su controlador en un solo lugar para todos los puntos finales en su API. También facilita que su API tenga una estructura de respuesta de excepción uniforme en todos los puntos finales. Esto simplifica el manejo de excepciones para sus clientes.

  • Este es el estándar y debería ser la respuesta aceptada de la OMI.

    – Honza Zidek

    14/09/2018 a las 15:15

  • ¿Qué pasa con el hecho de que no se recomienda manejar el flujo de aplicación esperado a través de Excepciones en Java? Por ejemplo, getCustomerForIBAN devuelve un Opcional expuesto a través de una API REST GET /api/customer/{iban} que devuelve 200 ok o 404 no encontrado? ¿Aconsejaría lanzar una excepción y manejarla de la misma manera?

    – LucasSolar

    18/07/2019 a las 20:55


  • Si desea evitar el uso de excepciones en Java, puede diseñar su método de controlador para que devuelva un ResponseEntity. ResponseEntity le permite controlar el código de estado HTTP que se devuelve, y es un tipo genérico para que pueda devolver cualquier estructura de objeto. Aquí hay una explicación sobre cómo usarlo: baeldung.com/spring-response-entity

    – Marcos normando

    19 de julio de 2019 a las 14:46


  • ¿Es este realmente el estándar para manejar “errores de validación”? Los errores de validación están destinados a ser un flujo controlado en su capa de servicio (presumiblemente). ¿Por qué dejaríamos que una Excepción subiera al nivel del Controlador sin manejar? Entiendo las excepciones inesperadas (es decir, los códigos de error 5xx), pero no las de validación (4xx). ¿Me estoy perdiendo de algo?

    – taylorcressy

    7 julio 2020 a las 22:17


  • Este es el estándar para manejar errores que otras capas de la aplicación permiten propagar o lanzar explícitamente. RE: errores de validación, la capa de servicio aún puede detectar y manejar. Fui demasiado restrictivo cuando dije “manejar errores de validación” en la primera oración. Eliminé “validación” para indicar que esto es para errores en general. Gracias por señalar eso.

    – Marcos normando

    7 julio 2020 a las 23:49


Avatar de usuario de Saravana
Saravana

Puede devolver un comodín genérico <?> regresar Success y Error en un mismo método de asignación de solicitudes

public ResponseEntity<?> method() {
    boolean b = // some logic
    if (b)
        return new ResponseEntity<Success>(HttpStatus.OK);
    else
        return new ResponseEntity<Error>(HttpStatus.CONFLICT); //appropriate error code
}

@Mark Norman respuesta es el enfoque correcto

  • Su único caso es que las herramientas de calidad de código (como Sonar Lint) marcan esta práctica de codificación con Los tipos de comodines genéricos no deben usarse en los parámetros de retorno (squid:S1452)

    – Sabir Kan

    12 de octubre de 2017 a las 4:05

  • Esto es más bien un cortar a tajos cómo eludir el mecanismo (imperfecto) de los genéricos de Java. La respuesta de @ MarkNorman es la estándar y debería ser la aceptada.

    – Honza Zidek

    14 de septiembre de 2018 a las 15:19

  • Acabo de encontrarme con el mismo problema y estoy buscando crear algo que funcione con VAVR Eitherpara que yo pudiera tener un public ResponseEntity<Either<Error, Success>> method() o mejor un public Either<ResponseEntity<Error>, ResponseEntity<Success>> method(). Creo que la forma de hacerlo sería crear un HttpMessageConverter eso sabría cómo manejar eso y simplemente convertiría el lado izquierdo/derecho y dejaría que suceda el procesamiento normal… de esa manera podría señalar mis estados válidos sin usar excepciones… ¿alguna idea sobre esto?

    –Dominik Dorn

    3 de febrero de 2019 a las 16:58


  • ¿Hay alguna forma de convertir un genérico comodín en un genérico específico?

    – Daniel Pablo

    31 de mayo de 2022 a las 7:44

Avatar de usuario de Sathiamoorthy
Sathiamoorthy

primavera 2 introducido ResponseStatusExceptionResponseStatusException usando esto puedes devolver Cadena, código de estado HTTP diferente, DTO en el Mismo tiempo.

@PostMapping("/save")
public ResponseEntity<UserDto> saveUser(@RequestBody UserDto userDto) {
    if(userDto.getId() != null) {
        throw new ResponseStatusException(HttpStatus.NOT_ACCEPTABLE,"A new user cannot already have an ID");
    }
    return ResponseEntity.ok(userService.saveUser(userDto));
}

Avatar de usuario de Maulik Patel
Maulik Patel

no estoy seguro, pero creo que puedes usar @ResponseEntity y @ResponseBody y enviar 2 diferentes uno es Éxito y el segundo es un mensaje de error como:

@RequestMapping(value ="/book2", produces =MediaType.APPLICATION_JSON_VALUE )
@ResponseBody
Book bookInfo2() {
    Book book = new Book();
    book.setBookName("Ramcharitmanas");
    book.setWriter("TulasiDas");
    return book;
}

@RequestMapping(value ="/book3", produces =MediaType.APPLICATION_JSON_VALUE )
public ResponseEntity<Book> bookInfo3() {
    Book book = new Book();
    book.setBookName("Ramayan");
    book.setWriter("Valmiki");
    return ResponseEntity.accepted().body(book);
}

Para más detalles, consulte esto:
http://www.concretepage.com/spring-4/spring-4-mvc-jsonp-example-with-rest-responsebody-responseentity

Puede usar un mapa con su objeto o cadena como a continuación:

@RequestMapping(value = "/path", 
        method = RequestMethod.GET, 
        produces = MediaType.APPLICATION_JSON_VALUE)
    @ResponseBody
    public ResponseEntity<Map<String,String>> getData(){

    Map<String,String> response = new HashMap<String, String>();

    boolean isValid = // some logic
    if (isValid){
        response.put("ok", "success saving data");
        return ResponseEntity.accepted().body(response);
    }
    else{
        response.put("error", "an error expected on processing file");
        return ResponseEntity.badRequest().body(response);
    }

}

Avatar de usuario de Maria Ines Parnisari
María Inés Parnisari

Aquí hay una manera en que lo haría:

public ResponseEntity < ? extends BaseResponse > message(@PathVariable String player) { //REST Endpoint.

 try {
  Integer.parseInt(player);
  return new ResponseEntity < ErrorResponse > (new ErrorResponse("111", "player is not found"), HttpStatus.BAD_REQUEST);
 } catch (Exception e) {


 }
 Message msg = new Message(player, "Hello " + player);
 return new ResponseEntity < Message > (msg, HttpStatus.OK);

}

@RequestMapping(value = "/getAll/{player}", method = RequestMethod.GET, produces = MediaType.APPLICATION_JSON_VALUE)
public ResponseEntity < List < ? extends BaseResponse >> messageAll(@PathVariable String player) { //REST Endpoint.

 try {
  Integer.parseInt(player);
  List < ErrorResponse > errs = new ArrayList < ErrorResponse > ();
  errs.add(new ErrorResponse("111", "player is not found"));
  return new ResponseEntity < List < ? extends BaseResponse >> (errs, HttpStatus.BAD_REQUEST);
 } catch (Exception e) {


 }
 Message msg = new Message(player, "Hello " + player);
 List < Message > msgList = new ArrayList < Message > ();
 msgList.add(msg);
 return new ResponseEntity < List < ? extends BaseResponse >> (msgList, HttpStatus.OK);

}

Avatar de usuario de KARTHIKEYAN.A
KARTHIKEYAN.A

También puede implementar de esta manera para devolver el éxito y el error en un mismo método de asignación de solicitud, use la clase de objeto (clase principal de cada clase en Java): –

public ResponseEntity< Object> method() {                                                                                                                                                                                                                                                                                                                                                                                  
    boolean b = //  logic  here   
      if (b)  
        return new ResponseEntity< Object>(HttpStatus.OK);      
    else      
        return new ResponseEntity< Object>(HttpStatus.CONFLICT); //appropriate error code   
}

¿Ha sido útil esta solución?