Versiones comparadas

Clave

  • Se ha añadido esta línea.
  • Se ha eliminado esta línea.
  • El formato se ha cambiado.

...

Tabla de contenidos
maxLevel4

...

Buenas Prácticas

Las principales indicaciones a la hora de construir una respuesta en un servicio REST (tanto para éxito como para error) son:

...

Bloque de código
languagejava
themeEclipse
titleEjemplo ResponseEntity
collapsetrue
    //EJEMPLO ResponseEntity con éxito
	public ResponseEntity<String> simpleAsyncTask( @RequestParam( defaultValue = "60" ) long t,
			@RequestParam( defaultValue = "1" ) long sleep ) throws InterruptedException {

		String result = "";
		log.info( "Entro en simpleAsyncTask {} - {}", t, sleep );

		final CompletableFuture<String> asyncStatus = service.asyncMethod( sleep * 1000, t );
		result = asyncStatus.getNow( "ko" );
		log.info( "Salgo de simpleAsyncTask" );

		return ResponseEntity.ok( result );
	}

    //EJEMPLO ResponseEntity con error
	@ExceptionHandler( TestLocalHandlerException.class )
	public ResponseEntity<TestLocalHandlerError> handleTestLocalHandler( TestLocalHandlerException ex ) {

		final TestLocalHandlerError error = TestLocalHandlerError.builder()
				.estado( HttpStatus.INTERNAL_SERVER_ERROR ).fecha( LocalDateTime.now() )
				.mensaje( ex.getMessage() ).build();

		return ResponseEntity.status( HttpStatus.INTERNAL_SERVER_ERROR ).body( error );

	}


...

Guía detallada  

Spring Boot proporciona varios mecanismos para capturar excepciones (global o localmente) y devolver mensajes de error (estándar o personalizados). Estos mecanismos han ido evolucionando con las diversas versiones del framework y, en algunos casos, pueden llegar a solaparse.

...

A continuación se va a explicar estos mecanismos desde el enfoque de los casos de uso más habituales:

  1. ResponseStatusException => Devolver modelo de respuesta estándar de forma rápida y correcta .
  2. DefaultErrorAttributes => Modificar el modelo de respuesta de forma global.
  3. ExceptionHandler => Manejar localmente una excepción propia y devolver el modelo de respuesta estándar o un modelo propio.
  4. ControllerAdvice => Manejar de forma global todas mis excepciones y devolver el modelo de respuesta estándar o un modelo propio.
  5. ControllerAdvice + ResponseEntityExceptionHandler => Modificar el comportamiento y el modelo de respuesta para excepciones internas capturadas por Spring Boot.
  6. [EXTRA] Bean Validation => Modificar la respuesta si se usa este estándar para la validación de los parámetros.


1. ResponseStatusException

Útil para devolver un error de forma correcta y rápida, sin preocuparnos de los datos devueltos.

Se construye la excepción pasándole el status code HTTP de error deseado y Spring Boot la captura y maneja de forma automática.
Devuelve el modelo de respuesta estándar (ver siguiente apartado).

...

Bloque de código
languagejson
titleResponse ResponseStatusException
{
    "fecha": "05/10/2021 10:31:27",
    "estado": "INTERNAL_SERVER_ERROR",
    "mensaje": "2. ResponseStatusException con FundeWebJSErrorAttributtes",
    "tipoRespuesta": "CUSTOM_DefaultErrorAttributes"
}


1.1 ResponseStatus:

La excepción ResponseStatusException es una evolución de otro mecanismo, la notación @ResponseStatus .
Por comodidad se recomienda usar ResponseStatusException, pero es posible seguir usando esta notación declarándola en nuestras excepciones y lanzándolas desde nuestra API REST directamente. 
Ver: Ejemplo ResponseStatus (https://gitlab.um.es/mncs/fundewebjsshowcase-api/-/blob/desarrollo/src/main/java/es/um/atica/fundewebjsshowcasebackend/exceptions/TestResponseStatusException.java).

Ejemplo de uso:
 Se anota nuestra excepción con ResponseStatus y se lanza desde nuestro controlador Rest.

...

Bloque de código
languagejson
titleRespuesta con @ResponseStatus
{
    "fecha": "05/10/2021 10:45:25",
    "estado": "BAD_REQUEST",
    "mensaje": "1. Notación ResponseStatus con FundeWebJSErrorAttributtes",
    "tipoRespuesta": "CUSTOM_DefaultErrorAttributes"
}


...

2. DefaultErrorAttributes

Por defecto Spring usa el modelo de respuesta (los campos que se devuelven) devuelto por la clase DefaultErrorAttributes.
Podemos modificar el modelo de respuesta estándar extendiendo esta clase (y anotándola con @Component).

...

Advertencia

No se recomienda desarrollar modelos propios de respuesta estándar hasta que se complete la integración con el RFC 7807 Problem Details for HTTP APIs por parte de MNCS.


...

3. ExceptionHandler

En los métodos anteriores se ha explicado cómo lanzar excepciones en nuestros servicios y modificar el modelo de respuesta.
A partir de este punto se explicará cómo maneja Spring las excepciones y cómo modificar este mecanismo.
Esto permitirá gestionar las respuestas, definir modelos de respuesta diferentes dependiendo de cada excepción, y sobreescribir el comportamiento estándar en situaciones de error no controladas.

...

Bloque de código
languagejson
titleRespuesta
{
    "estado": "INTERNAL_SERVER_ERROR",
    "fecha": "05/10/2021 12:37:46",
    "mensaje": "3. Excepción con handler local y modelo custom TestLocalHandlerError",
    "tipoRespuesta": "CUSTOM_LocalHandler"
}

...



4. ControllerAdvice

El principal inconveniente del mecanismo anterior es que, si queremos manejar la misma excepción en varios controllers, habría que escribir el mismo método en cada uno de ellos.

...

Bloque de código
languagejson
titleRespuesta JSON
{
    "estado": "INTERNAL_SERVER_ERROR",
    "fecha": "05/10/2021 01:37:25",
    "mensaje": "4. Excepción con ControllerAdvice y modelo custom TestControllerAdviceError",
    "tipoRespuesta": "CUSTOM_ControllerAdvice",
    "erroresValidacion": null
}


...

5. ControllerAdvice + ResponseEntityExceptionHandler

Según la documentación de Spring, existe una clase que proporciona un manejo centralizado de todas las excepciones en métodos anotados con @RequestMapping a través de la notación @ExceptionHandler. Se trata de la clase ResponseEntityExceptionHandler.
Es decir, si queremos usar nuestro ControllerAdvice declarado en el ejemplo anterior, y ampliarlo para modificar las respuestas en toda tipo de excepciones (internas o propias), solo tenemos que extender la clase ResponseEntityExceptionHandler.

...

Fuente: TestControllerAdvice.java (https://gitlab.um.es/mncs/fundewebjsshowcase-api/-/blob/desarrollo/src/main/java/es/um/atica/fundewebjsshowcasebackend/handler/TestControllerAdvice.java)

...

6. Bean Validation

Si estamos utilizando el estándar Bean Validation para realizar la validación de parámetros (path o request), posiblemente queramos capturar la excepción lanzada automáticamente para cambiar el mensaje (para incluir los errores de validación) y el código de respuesta HTTP (para devolver un 400 Bad Request en lugar de un 500).

...

Info

La configuración y uso de Bean Validation queda como objetivo de la página de confluence: [EN CONSTRUCCIÓN]. Ante cualquier duda contacte con MNCS o revise las fuentes del proyecto de ejemplo fundewebjsshowcase-api.



...

Conclusión


Enumerar conclusiones, si se quiere hacer rápido usar ResponseStatusException, si se quiere cambiar la respuesta o el modelo y tenemos muchas excepciones usar ControllerAdvice + ResponseEntityExceptionHandler.

...

Info

Próximamente estará disponible la integración con el RFC Problem, por lo que no se recomienda elaborar muchos modelos de respuesta propios.

Estará disponible un modelo de respuesta común para las aplicaciones FundeWebJS y se indicará cómo manejar las excepciones de forma más ágil.



Artículos Relacionados

...