Spring boot edit json exception with data from server response - java

My spring boot application works like a middleman. It waits for a request, then formats this request and sends to the server and returns server response to request sender. However when I get response error response from server (For example with status code 400 Bad Request) I want to modify default spring boot JSON exception body by adding error cause which was returned from server in JSON format.
Response from server:
Http status: 400
{
"type": "InvoiceDto",
"currency": "EUR",
"error_code": "NO_AMOUNT"
"error_message": "amount is not set"
"invoice_status": "FAILED",
"payment_id": "20516324",
"order_id": 1209,
}
Spring boot returns exception:
{
"timestamp": 1493211638359,
"status": 500,
"error": "Internal Server Error",
"exception": "org.springframework.web.client.HttpClientErrorException",
"message": "400 Bad Request",
"path": "/sms"
}
I want to edit spring's exception field "message" with server's returned "error_message" value. But it seems that I can't even get Response body because spring boot automatically throws default exception.

My understanding is that you need to provide your own exception mapper. The one used now is the default ErrorController added by autoconfiguration.
The correct way is to define your own ResponseEntityExceptionHandler
you can read about custom Exceptionmappers here

Related

How to handle 404 exceptions using #ControllerAdvice and #ExceptionHandler?

I have a problem with Spring's exception handling for controllers. I have a class annotated with #RestControllerAdvice with a couple of #ExceptionHandler's, like this:
#ExceptionHandler(HttpRequestMethodNotSupportedException::class)
fun methodNotSupportedException(
exception: HttpRequestMethodNotSupportedException,
request: HttpServletRequest
): ResponseEntity<ApiError> {
logger().error("Method not supported: {}", exception.message)
val methodNotAllowed = HttpStatus.METHOD_NOT_ALLOWED
val apiError = logAndBuildApiError(request, methodNotAllowed, exception)
return ResponseEntity(apiError, methodNotAllowed)
}
and they work perfectly fine. In this case, when I'm trying to use an non-implemented HTTP method like POST:
{
"requestUri": "/api/v1/items",
"status": 405,
"statusText": "Method Not Allowed",
"createdAt": "2023-01-12T16:50:36.55422+02:00",
"errorMessage": "Request method 'POST' not supported"
}
What I would like to achieve is to handle situations when someone is trying to reach an non-existing endpoint, i.e. the correct one is GET http://localhost:8080/api/v1/items.
But when I'm trying to reach http://localhost:8080/api/v1/itemss, which is of course nonexistent, I recieve a regular Spring whitelabel error page, but I would like to receive a JSON like in the former example:
{
"requestUri": "/api/v1/itemss",
"status": 404,
"statusText": "Not Found",
"createdAt": "2023-01-12T16:52:06.932108+02:00",
"errorMessage": "Some error message"
}
How do I implement a #ExceptionHandler so it could handle exceptions related to non-existing resources?
spring.mvc.throw-exception-if-no-handler-found works in conjunction with
spring.mvc.static-path-pattern. By default, the static path pattern is /**, which includes the whitelabel error pages that you're seeing.
See https://github.com/spring-projects/spring-boot/pull/31660
and https://gitter.im/spring-projects/spring-boot?at=62ba1378568c2c30d30790af
and https://docs.spring.io/spring-boot/docs/current/reference/htmlsingle/#web.servlet.spring-mvc.static-content
Option one is to set these two properties in your configuration.
spring:
mvc:
throw-exception-if-no-handler-found: true
static-path-pattern: /static
Option 2 is to add #EnableWebMvc to your spring boot application, and set the spring.mvc.throw-exception-if-no-handler-found property to true. By adding EnableWebMvc you'll be getting the WebMvcConfigurationSupport bean, which will cause Spring not to initialize the WebMvcAutoConfiguration and thereby not set the static-path-pattern.

Why am I getting 403 forbidden when I try to validate JWT from Zuul Proxy?

I have registered authentication-service on Eureka and authenticating using Zuul proxy. This the application.properties file of the Zuul service:
server.port=8090
zuul.routes.authentication-service.url=http://localhost:8095
ribbon.eureka.enabled=false
zuul.sensitive-headers=Set-Cookie,Authorization
http://localhost:8095/login is mapped for authentication and http://localhost:8095/validate for validating the token. Because of zuul proxy, I can access those resources from http://localhost:8090/authentication-service/. The /login mapping is working fine but when I try http://localhost:8090/authentication-service/validate and pass the token in "Authorization", I get "Access Denied". This is what I have in Postman:
{
"timestamp": "2020-09-18T09:30:35.543+00:00",
"status": 403,
"error": "Forbidden",
"message": "Access Denied",
"path": "/validate"
}
But when I pass the same token http://localhost:8095/validate, I get the desired result.
What am I missing here? Was there an issue passing token from Zuul? How can I fix this?
You have to remove Authorization in your sensitive-headers configuration.
Zuul automatically remove headers specified in sensitive headers.
So your token is removed from your request.

Customize Spring Boot error response code without changing the default body

Spring Boot by default returns a response body for exceptions that meets my needs out of the box:
{
"timestamp": 1587794161453,
"status": 500,
"error": "Internal Server Error",
"exception": "javax.persistence.EntityNotFoundException",
"message": "No resource exists for the given ID",
"path": "/my-resource/1"
}
However, I would like to customize the response code for different types of exceptions thrown by my application. Some of the exceptions are not ones I own, so I can't just stick a #ResponseStatus annotation on the exception class. I've tries using an #ExceptionHandler method with #ResponseStatus, but that is overwriting the response body, which I don't wish to happen. For instance, I would like to map javax.persistence.EntityNotFoundException to return status code 404.
#ExceptionHandler
#ResponseStatus(HttpStatus.NOT_FOUND)
public void handleEntityNotFoundException(EntityNotFoundException e) {
// This method returns an empty response body
}
This question is similar to mine, but it is also attempting to adjust the response body. I am hoping that there is a shorter, more idiomatic way of adjusting just the status code and not the body.
It turns out that this answer to the question I mentioned had the exact solution needed to solve this problem, even though it didn't quite fully the question asked. The trick was dropping the use of #ResponseStatus from the method, and manually setting the status on the HttpServletResponse using HttpServletResponse.sendError(). This serves the standard Spring Boot exception response, but with the updated status code.
#ExceptionHandler
public void handleEntityNotFoundException(EntityNotFoundException e, HttpServletResponse response) throws IOException {
response.sendError(HttpServletResponse.SC_NOT_FOUND);
}
{
"timestamp": 1587794161453,
"status": 404,
"error": "Not Found",
"exception": "javax.persistence.EntityNotFoundException",
"message": "No resource exists for the given ID",
"path": "/my-resource/1"
}

Proper Handling of PropertyReferenceException for Query Params

In a Spring (Boot) application we're heavily using the Pageable interface and have our controller methods mostly defined like so:
public ResponseEntity<List<Thing>> fetchAll(Pageable pageable) {
Page things = this.thingService.findAll(pageable);
return new ResponseEntity<>(things.getContent(), HttpStatus.OK);
}
When accessing it via the following endpoint:
/api/things/?size=5&page=1&sort=name,asc
If the sort property, name in this case, is misspelled or doesn't exist, a PropertyReferenceException is thrown and a 500 sent back to the user with a message such as:
{
"timestamp": "2017-01-30 13:40:47",
"status": 500,
"error": "Internal Server Error",
"exception": "org.springframework.data.mapping.PropertyReferenceException",
"message": "No property name found for type Thing!",
"path": "/api/things"
}
While this is technically the right error message, it doesn't seem like 500 is the appropriate code to respond with. 5xx level message are typically reserved for server issues and this is technically a user issue so more like a 4xx level message.
Best I can see if that maybe it's just a 400. My question is a) is 400 an appropriate response in this situation and b) is there an elegant way to handle this. My current solution is to catch that Exception in my ControllerAdvice class and just return the 400.

How does Spring Security BadCredentialsException mapped to HTTP 401 code

When i throw a org.springframework.security.authentication.BadCredentialsException exception, in client it will display 401 as below,
{
"timestamp": "2016-03-29T09:07:50.866+0000",
"status": 401,
"error": "Unauthorized",
"message": "Some message",
"path": "/test/service1/getAll"
}
I want to know where and how does the BadCredentialsException mapped to HTTP 401 Status code?
It's ExceptionTranslationFilter that handles exceptions thrown by the security interceptors and provides suitable HTTP responses:
The ExceptionTranslationFilter sits above the
FilterSecurityInterceptor in the security filter stack. It doesn’t do
any actual security enforcement itself, but handles exceptions thrown
by the security interceptors and provides suitable and HTTP responses.
Check out the Spring Security documentation for more information here and here.

Categories

Resources