En el proyecto en el que estoy trabajando ahora tenemos una API de servicios Rest hecha con Spring Boot y documentada usando Swagger. Existe una clase anotada con @RestControllerAdvice
para personalizar la respuesta de error. He observado que cuando sucede un error 404 no se está ejecutando el método correspondiente por lo que, el JSON de error retornado, tiene el formato por defecto de Spring. Para que esto no suceda.
En el fichero application.properties
spring.mvc.throw-exception-if-no-handler-found=true spring.resources.add-mappings=false
Implementar @RestControllerAdvice
@RestControllerAdvice public class MyControllerAdvice { @ExceptionHandler(NoHandlerFoundException.class) public ResponseEntity<?> handleControllerException(HttpServletRequest request, NoHandlerFoundException ex) { LOGGER.debug("handleControllerException. message: {}", ex.getMessage()); // Return custom response entity } }
Con esto ya responde con el formato de JSON que esperábamos.
Hacer funcionar Swagger UI
Al añadir la propiedad spring.resources.add-mappings
esta solución vemos que deja de funciona Swagger UI. Da este error:
org.springframework.web.HttpMediaTypeNotAcceptableException: Could not find acceptable representation
El problema es que el autoconfigurador mvc de spring mapea recursos por defecto que son los que utiliza Swagger para mostrar su página web.
Finalmente copio el código del autoconfigurador pero hago que en lugar de aplicar a todas las url "/**"
aplique sólo a "/swagger-ui.hml"
tal y como se puede ver en el siguiente código:
@Configuration @EnableWebMvc public class MyWebMvcConfigurerAdapter extends WebMvcConfigurerAdapter { @Override public void addResourceHandlers(ResourceHandlerRegistry registry) { registry.addResourceHandler("/webjars/**") .addResourceLocations("classpath:/META-INF/resources/webjars/"); registry.addResourceHandler("/swagger-ui.html") .addResourceLocations(getStaticLocations()); } private String[] getStaticLocations() { return new String[]{ "/", "classpath:/META-INF/resources/", "classpath:/resources/", "classpath:/static/", "classpath:/public/" }; } }