I use exception handler in my controllers like this:
#ExceptionHandler(Exception.class)
#ResponseStatus(HttpStatus.CONFLICT)
#ResponseBody
public ApiError handleException(Exception e) {
logger.error("Exception occurred {}", e.getMessage(), e);
return new ApiError(HttpStatus.CONFLICT, e.getMessage());
}
Now I thought about choosing the right response status depends on exception type. Is there any relation in best practices?
The modern way is using Runtime exception everywhere so am not sure that it is always correct to use 4XX response codes for all Runtime exceptions.
Could you clarify?
P.S.
I understans that 4XX is client error, but 5XX is server error.
IMHO it just does not depend on a runtime vs checked exception pattern, but on a semantically right differentiation.
The type of exceptions does not reflect this semantic by default.
5xx is telling the client that something went wrong at you side.
4xx is telling the client that the API is used "wrong" or not in an expected way.
You can implement a 4xx or 5xx status code with runtime or checked exceptions. It just depends on your own software architecture.
I would not determine 4xx/5xx from the differentiation of checked or runtime exceptions (seems to harm the principle of least astonishment - POLA)
Personally, I just throw a custom Exception back to the controller when something goes wrong at runtime, and a ResponseEntity is automatically created, returning my Exception with a HttpStatus code. I try to keep as often as possible a logic, and to return the clearer code along with the message and the exception string name.
Like :
HttpStatus.PRECONDITION_FAILED when a pre-treatment fail (not because of the client payload tho)
HttpStatus.BAD_REQUEST when something is wrong in the payload received from client
HttpStatus.NO_CONTENT when something is OK but we return empty response cause no result is found
etc ...
You are on the right track. In my opinion, it is not always correct to return 4xx response codes for all unchecked exceptions. I would rather map a defined subset of those exceptions to 4xx response codes and anything else should be an internal server error, thus 500 response code.
#ResponseStatus(value=HttpStatus.NOT_FOUND)
public class EntityNotFoundException extends RuntimeException {
// ...
}
This exception can be thrown from #Service annotated classes if the entity is not found. For the other cases, you could define custom exceptions as well. You can also stick to you #ExceptionHandler, but then you would have to do the mapping yourself.
I should be good practise to map exceptions to related HTTP response codes:
Bad Request: 400
Not Found: 404
Forbidden: 403
Internal Server Error: 500
Also, do not forget to return one of the following (or any other) response code, if your request was successful.
OK: 200
Created: 201
Above response codes are commonly used. Of course, there are a lot more, but most APIs only take a small subset. With correct mapping, it is easier for clients to know what possibly went wrong (or right) and then can carry out further actions or display the client neccessary information. For example:
200: show a success message
403: redirect to the login page
400: show errors if a form was submitted
It is also good practise to include meaningful information in the body if anything went wrong. This answers also the question: "What should i do if i cannot map an exception to an existing response code?". I have asked myself the same question and the answer is simple. Try to map it to the closest response code and include anything else in the body.
If the client is missing a parameter you could use the following:
{ "error" : "Bad Request - Your request is missing parameter 'id'. Please verify and resubmit." }
Or for above mentioned forms errors (response code 400):
{
"errors": [
"username": "AlreadyInUse",
]
}
Just make sure you stick to one format when returning information in the body. Otherwise, it is a pain to work with.
Related
I'm writing a Web application that makes downstream calls using RestTemplate. If the underlying service returns a 401 Unauthorized, I want to also return a 401 to the calling application; the default behavior is to return a 500. I want to keep the default Spring Boot error response as provided by BasicErrorController; the only change I want is to set the status code.
In custom exceptions, I'd just annotate the exception class with #ResponseStatus, but I can't do that here because HttpClientErrorException.Unauthorized is provided by Spring. I tried two approaches with #ControllerAdvice:
#ExceptionHandler(HttpClientErrorException.Unauthorized.class)
#ResponseStatus(UNAUTHORIZED)
public void returnsEmptyBody(HttpClientErrorException.Unauthorized ex) {
}
#ExceptionHandler(HttpClientErrorException.Unauthorized.class)
#ResponseStatus(UNAUTHORIZED)
public void doesNotUseBasicErrorController(HttpClientErrorException.Unauthorized ex) {
throw new RuntimeException(ex);
}
How can I configure MVC to continue to use all of the built-in Boot error handling except for explicitly overriding the status code?
The below code works for me -- in an app consisting of a #RestController whose one method consisted of throw new HttpClientException(HttpStatus.UNAUTHORIZED), running on an embedded Tomcat. If you're running on a non-embedded Tomcat (or, I suspect, on an embedded non-Tomcat) odds are you'll have to do something at least somewhat different, but I hope this answer is at least somewhat helpful anyway.
#ControllerAdvice
public class Advisor {
#ExceptionHandler(HttpClientException.class)
public String handleUnauthorizedFromApi(HttpClientException ex, HttpServletRequest req) {
if (/* ex instanceof HttpClientException.Unauthorized or whatever */) {
req.setAttribute(RequestDispatcher.ERROR_STATUS_CODE, 401);
}
return "forward:/error";
}
}
Explanation: when a HttpClientException is thrown while we're processing request X (in an embedded servlet), what normally happens is that it bubbles all the way up to some org.apache class. (I might fire the debugger up again and work out which one, but this is a pretty high-level explanation so it doesn't matter much.) That class then sends request X back to the application, except this time the request goes to "/error", not to wherever it was originally going. In a Spring Boot app (as long as you don't turn some autoconfiguration off), that means that request X is ultimately processed by some method in BasicErrorController.
OK, so why does this whole system send a 500 to the client unless we do something? Because that org.apache class mentioned above sets something on request X which says "processing this went wrong". It is right to do so: processing request X did, after all, result in an exception which the servlet container had to catch. As far as the container is concerned, the app messed up.
So we want to do a couple of things. First, we want the servlet container to not think we messed up. We achieve this by telling Spring to catch the exception before it reaches the container, ie by writing an #ExceptionHandler method. Second, we want the request to go to "/error" even though we caught the exception. We achieve this by the simple method of sending it there ourselves, via a forward. Third, we want the BasicErrorController to set the correct status and message on the response it sends. It turns out that BasicErrorController (working in tandem with its immediate superclass) looks at an attribute on the request to determine what status code to send to the client. (Figuring this out requires reading the class's source code, but that source code is on github and perfectly readable.) We therefore set that attribute.
EDIT: I got a bit carried away writing this and forgot to mention that I don't think using this code is good practice. It ties you to some implementation details of BasicErrorController, and it's just not the way that the Boot classes are expected to be used. Spring Boot generally assumes that you want it to handle your error completely or not at all; this is a reasonable assumption, too, since piecemeal error handling is generally not a great idea. My recommendation to you -- even if the code above (or something like it) does wind up working -- is to write an #ExceptionHandler that handles the error completely, meaning it sets both status and response body and doesn't forward to anything.
You can customize the error handler of the RestTemplate to throw your custom exception, and then handle that exception with the #ControllerAdvice as you mentioned.
Something like this:
#Configuration
public class RestConfig {
#Bean
public RestTemplate restTemplate(){
// Build rest template
RestTemplate res = new RestTemplate();
res.setErrorHandler(new MyResponseErrorHandler());
return res;
}
private class MyResponseErrorHandler extends DefaultResponseErrorHandler {
#Override
public void handleError(ClientHttpResponse response) throws IOException {
if (HttpStatus.UNAUTHORIZED.equals(response.getStatusCode())) {
// Throw your custom exception here
}
}
}
}
I am writing a web application using Spring Boot that frequently updates data on the back end and returns the updated object to reflect the update on the front end.
The question I have is what to return from my methods if the update should fail for some reason.
I am currently returning the object as it was received should it fail but as it stands the state on the front end would not reflect the failure on the back end in the case that it occurs.
I want to return the object to update the state but doing so prevents me from returning a String or HttpStatus indicating a problem doesn't it? Returning the old object doesn't seem a good solution either.
You can throw an exception in this case of failure from your REST controller.
To handle this exception, Spring provides ResponseEntityExceptionHandler callback class with the help of which you can handle the thrown exception and set different headers in the response entity.
So on client-side, you can recognise that some failure is occurred on server side.
You can set HttpStatus as HttpStatus.INTERNAL_SERVER_ERROR and add more details in the body.
The question I have is what to return from my methods if the update should fail for some reason.
You first need to determine whether the error was caused by the client or by the server, then you can determine the most suitable status code to be returned, either in the 4xx or in the 5xx range. See this answer which may give you some insights.
Instead of returning the request request back in the response, you should return a payload that describes what the problem was. Consider, for example, the payload defined in the RFC 7807 along with the application/problem+json media type.
Finally, this answer may give you insights on how to map an exception to a HTTP status code in Spring:
You can map exceptions to responses by annotating an exception class with #ResponseStatus.
It also gives you the possibility to implement a HandlerExceptionResolver or extend one of the existing implementations, such as the AbstractHandlerExceptionResolver.
Another approach would be using a ResponseEntityExceptionHandler annotated with #ControllerAdvice and define the handled exceptions by annotating the implemented method with #ExceptionHandler.
I have a scenario :
UI<--->Spring boot micro-service REST API<--->server
Now, there is a situation in which I want to handle custom exceptions(which I am aware how to do) in order to return specific Http Status and message back to UI when server responds in certain manner for e.g. 500 should return "Please return after a while" insteal of "internal server error". The maven project for our micro-service is divided into 3 layers (sub maven projects) i.e. Business, Web and Domain. Where web contains controller class, Business contains Service class and Domain contains #Entity, #Components etc.
I want to know in order to handle the above mentioned exception let say HTTP Status 500, should be done at business layer? or at web layer i.e. controller level. What would be the best possible solution? (I am aware of ResponseEntity and how it can provide a customized response to UI).
I personally believe that if I include custom exception class at Business Level and return that in Controller class using response entity after checking the response status would do the trick. But officials feel that it should be done at service level? I am not able to understand why(it makes the process more complex)? can anyone suggest which solution is best?
Officials are right, it should be in Service Layer. I would say best practice would be to use #ExceptionHandler. As the downside to handling the exception in the controller method is that it makes the code less readable and might be repeated across many controller methods.
I would recommend having a base class for your controllers with the #ExceptionHandler defined. This way it can be used for many different controllers, without any code duplication. This would be more readable than the exception resolver approach, but could be used in conjunction
This is clearly explained here
If you want to handle error in a global level, you can use #ControllerAdvice which is very easy when comes to the handling custom exceptions as well as runtime exceptions.
you can throw exceptions from business layer to web controllers and define a #ControllerAdvice class to catch those errors and provide responses with correct response status.
For Ex:-
#ControllerAdvice
public class RestResponseEntityExceptionHandler extends ResponseEntityExceptionHandler {
#ExceptionHandler(value = { IllegalArgumentException.class, IllegalStateException.class })
protected ResponseEntity<Object> handleConflict(RuntimeException ex, WebRequest request) {
String bodyOfResponse = "This should be application specific";
return handleExceptionInternal(ex, bodyOfResponse,
new HttpHeaders(), HttpStatus.CONFLICT, request);
}
}
and throw those Exception classes from the controller classes also, you dont need to catch exception from the controllers.
Hope this helps to you...
Above code snipplet i took from here
Error response is usually generated by #ExceptionHandler matching your exception type and maybe registered with #ConrtrollerAdvice as described here.
API should be standardised (e.g. http://jsonapi.org/) and designed primarily for developers. Returning "Please return after a while" instead of "Internal Server Error" makes little sense to me. It's a 500 HTTP status response of uncertain reason e.g. NullPointerException somewhere deep in the code.
I am currently developing REST services and throwing BadRequestException for all of the following,
1. Path parameter is invalid
2. Query parameter is invalid
4. Input request object has missing attributes
Is there any specific exceptions for each case like InvalidParameterException or so..? Is there any documentation available to learn which exceptions should be thrown on what situations?
I think it's a personal decision and the answer will depend on your needs to have more detailed expceptions or not.
There are two ways to handle errors with JAX-RS:
Throwing a WebApplicationException
That's the approach you are using, which allows you to map exceptions that extend WebApplicationException to HTTP error responses.
I think throwing a BadRequestException is just fine for all the situations mentioned in your question. Just remember adding a detailed message explaining what was wrong.
If you need a more specific exception, you could consider extending the BadRequestException or maybe the ClientErrorException. The new exceptios could encapsulate the message which explains what the problem with the request. It's up to your needs.
For more details on the exceptions provided by the JAX-RS API, have a look at the javax.ws.rs package documentation. If they do not fit your needs, just extend them and create your specific exceptions.
Using an ExceptionMapper
In other cases it may not be appropriate to throw instances of WebApplicationException, or classes that extend WebApplicationException, and instead it may be preferable to map an existing exception to a response. For such cases it is possible to use a custom exception mapping provider.
Consider, for example, you decide to throw an IllegalArgumentException whenever you received an inapropriate value for your query or path parameters. You can create an ExceptionMapper to map the IllegalArgumentException to a response with the 400 status code:
#Provider
public class IllegalArgumentExceptionMapper
implements ExceptionMapper<IllegalArgumentException> {
#Override
public Response toResponse(IllegalArgumentException exception) {
return Response.status(400).entity(exception.getMessage())
.type("text/plain").build();
}
}
For more details, have a look at the Jersey documentation.
All 3 errors sound like client errors, as the client fails to abide by the contract - so I would return a HTTP 400 Bad Request - perhaps with an explanation in the body of the response.
I believe usually you would create separate cases depending on how you would like to handle these errors. For example, you will have 3 different exceptions to represent your errors.
Most frameworks then allow you to install ExceptionMappers. These map your exceptions to an HTTP response code. These are documented and you should follow them:
For example: http://www.restapitutorial.com/httpstatuscodes.html
In your case for example, I would throw IllegalArgumentExceptions for all those 3 cases and install a mapper, mapping this to a 400 response code with potentially some info.
This can be for example important since the client consuming your service will not receive your exceptions anyway, but rather analyse the response code of the request. With a 400, a user will then know that the request was invalid and won't be retried. You can have similar cases for all sorts.
To read about exception mappers, for example with the help of jersey:
https://jersey.java.net/documentation/latest/representations.html
So to your question:
No, I don't believe there is any best-practise on what Exceptions are thrown from your application. Usually REST frameworks don't have specific exception mappers other than a catch-all mapper that will return a 500 (Internal Server Error)
There is however documentation for REST and the HTTP with regards to which responses should be returned for specific use cases. You should try and design your REST endpoint to conform to those standards for maximum reusability and understandability.
I hope that helps,
Artur
I am trying to better handle bad responses when using the sprint rest client. My code is as follows:
ResponseEntity<Foo> response = null;
try {
response = restTemplate.exchange(uri, HttpMethod.GET,
new HttpEntity<>(new HttpHeaders()), Foo.class);
catch (RestClientException rce) {
//what to do here?
}
This works great as long as there is no error. The problem is that when the corresponding web service returns an error (or times out), I just get an exception. There is no enum with a status code where I could handle it as I wish. Sometimes the error message is useful. Sometimes not. Usually, if the corresponding server returns an html error page, I just get a message that the object cannot be created, but the specific error is swallowed.
Any ideas?
What can you get with rce.getMostSpecificCause()? Maybe there is some more information.
You can catch HttpStatusCodeException that is direct subclass of RestClientException which is more generic. There are a lot of exceptions that you can catch that are much more specific than RestClientException e.g.
public class HttpServerErrorException
extends HttpStatusCodeException
Exception thrown when an HTTP 5xx is received.
Look at the docs for RestClientException.
If the website you are querying returns an HTTP errorstatus then that should be reflected in the response object and you can switch through the statuses that you want to cover.
switch(response.getStatus()) {
case HTTPStatus.BAD_REQUEST: {
}
case HTTPStatus.BAD_GATEWAY: {
}
...
}
The RestClientException should only be thrown if there is a client side error, i.e. that's independent from the server response. (Spring Doc)