I have to design a DAO that makes a call to a REST WS.
This WS must return the user Credentials from the given username and password.
Case 1 : the user was found => the REST WS sends http code 200 and a credentials response.
Case 2 : the user was not found => the REST WS sends http code 400 and an error object with the cause.
Case 3 : the user was found but his account is disabled => the REST WS sends http code 400 and and error object with the cause.
Case 4 : the REST WS is not available
What is the best way in my DAO to map the REST WS response ?
1 - I throw funtionnal checked exceptions in my DAO to treat the error objects cases and i return credentials response objects in normal cases. When REST WS is unavailable, i throw an unchecked exception
2 - I don't throw any functionnal exception in my DAO, as it is the Service layer's job. I return what the REST WS is returning, ie credentials responses and error responses in a wrapped object for example and i let the Service layer check for these objects to do the right job. When REST WS is unavailable, i throw an unchecked exception
3 - I only throw unchecked exceptions for error cases and i let the service layer decide what to do with it. And i return only Credentials response.
Thank you very much in advance.
I prefer option 1 because your DAO is taking responsibility for understanding what the remote datasource is returning. Your service layer sits above your DAO and should not have to understand any intricacies of the remote source; this includes how errors are returned over the wire.
4XX responses in the HTTP protocol are defined as client errors and I think do qualify for throwing an exception in the DAO layer. The error object then just is a representation of the exception thrown.
If you should throw a checked or unchecked exception will probably be base for a long discussion and in the end depends on personal preference or general coding guidelines in the project. With throwing an exception you can map the exception type to the according HTTP error code e.g. BadCredentialsException becomes HTTP error 400 anything that can't be mapped becomes a 500 internal server error
Related
I have multiple #Service's in my Spring boot application which mainly make API calls to some external services.
Do Spring offers a custom Exception for a kind of a "404" exception? i.e. the item not found / there's no result for the requested key.
I'm aware of NoSuchElementException class but it doesn't seem to really fit here.
I guess I could create my own NoResultException but I'd like to follow the convention (if there's such)
Thanks!
There is no such exception provided by the Spring framework for the case of 404, or any other HttpStatus, for that matter.
You should ideally handle that in your service layer based on the API response and throw a custom exception which denotes the 404 case according to your domain. You can have a #ControllerAdvice which handles the specific exception and provides a custom response accordingly.
What you can use is HttpStatusCodeException. More details int the documentations. Example constructor is
HttpStatusCodeException(HttpStatus statusCode, java.lang.String statusText)
where you can provide your code, for example 404 and message. Thrown in service will be translated into the right http response.
Is it fine to throw an exception on the server side when the requested resource was not found?
the client receives a 404 not found. My concern is whether it is fine/wrong to throw an exception on the server side when this happens.
It's hard to assume what your are trying to do with the level of details you added to your question.
However, if you handle the exceptions properly, there may be nothing wrong with that approach. Have a look at the approaches used by some frameworks:
JAX-RS
You can throw a WebApplicationException, that will be mapped a response. You can define your own subclasses of WebApplicationException or use the existing ones. The NotFoundException, for example, will be mapped to a response with the 404 status code. For more details on the existing exceptions, refer to this answer.
You also can create your own ExceptionMapper to map any exception to a desired response.
Spring MVC
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
Basically it is not ideal to throw reserved status codes of exception. You should handle this exceptions internally and prepare your own code with meaning full message that client should know the actual problem.
I would say add a filter to capture 404 and add custom information about the 404 details.
In case of pure REST implementation, any resource-id missing and malformed URL will return 404.
As far as REST contract, both cases are correct to have 404 response. But more details on what type of resource is missing will help the client side consuming it to take appropriate actions.
Related discussion:
return-404-when-a-rest-resource-is-not-found
From perspective of semantics: Exception should be thrown if condition is such that condition is unrecoverable and devs must be notified about it.
Server cannot resolve auth request in the beginning of a session - this is serious enough situation and exception is appropriate.
User didn't fill out obligatory field and tried sending a form. This problem can be fixed and an exception would be a bad design.
In a web RESTful service, I need to call 3rd service, how can I graceful return the error message?
In my opinion, it's like this:
DB operate error
DBService layer, print the error stack in log, and throws Exception with a message simply describe the error reason, such as "record is not exist" or "primary key conflict" and so on.The rest service layer catch the Exception, and return 500 with this error message.
3rd system error
The service which call the 3rd system, log the error, and don't return the error stack in rest response, it only throws Exception with a message, such as "template is not exist" and so on.The rest service layer catch the Exception, and return 500 with this error message.
Actually, the flow for the two case is almost the same, I think it's very simple, but I don't know it is a good design.
I want to tell us more reasons about the error, but can't directly return the error call stack to user.
Yes, it is a good approach. You can throw your custom exceptions and yes, in the controller catch the exception and return the corresponding error code with message
I am creating a web service API following RESTful principles. In the service layer I have a method named:
/**
* #param answerId Id of the answer that will be deleted.
*/
void deleteAnswer(int answerId);
As you would expect this will delete the answer if the id of the answer is found in the system. Now, my question is:
Having this endpoint in the webservice:
HTTP DELETE /my-context/answers/{answerId}
the users of the API is able to add whatever id they want. They shouldn't, but they are able to. Because of that I want to throw an IllegalArgumentException from the service layer that I resolve HTTP message (Spring Web takes care of this). My other option would be to change the return type of the deleteAnswer method in the service layer so it returns true/false. What do you think?
If you return true false that means you are returning HTTP 200. While you should return 404. Spring has exception handler controller. You can throw your custom exception and define a exception handler which will send 404 with proper error message.
Returning an exception means that's an error to call your mehod like that. Returning true/false means that it's legal to call your service api like that.
Because you said "they shouldn't" I would go for exception.
I would rather use my own exception class that could be handled more cleanly than IllegalArgumentException.
Your web service should signal an error by specifying an appropriate status code, such as 400 or 404.
Your web service signature will then be:
ResponseEntity<Void> deleteAnswer(#PathVariable("answerId") int answerId);
You can throw an exception from the service layer, it's absolutely fine.
Then you could catch it in your 'deleteAnswer' method and return an appropriate status code.
Alternatively (and better), you can handle all the exceptions from all controllers in one place using
#ControllerAdvice class YourExceptionResolver {
#ExceptionHandler
public ResponseEntity<String> defaultErrorHandler(HttpServletRequest req, Exception e) {
//return status code 400, 404, or 500 based on the exception
//with String containing the error message
}
}
If you use #ControllerAdvice and exceptions from the service layer, you can keep your original signature 'void deleteAnswer(int answerId)'.
I don't like throwing exceptions for some reason, maybe because of the performance hit I don't know, wondering if I should re-think this issue.
Should my service layer (uses Dao's + business logic etc.) be throwing exceptions?
public ModelAndView createProduct(#Valid ProductForm productForm, ..) {
ModelAndView mav = new ModelAndView(...);
if(bindingResult.hasErrors()) {
return mav;
}
// throw exception if user doesn't have permissions??
productService.create(product, userPermissions);
}
So my options in the create method of the ProductService:
if the user doesn't have permissions, throw an exception
return some sort of a Response object that will have the new product Id if it was a success, along with a success/failure flag and a error collection.
Things to keep in mind:
I may re-use this service layer in a non-web app, also in a restful web service.
What is considered best practice?
Depends of what you mean by service and exception, but in the context you've got I'll assume a java exception from a HTTP endpoint.
The answer is no. Services should expose errors in a general way. In the case of Restful service, errors should be propagated as HTTP status with error codes. The service shouldn't leak implementation details to consumers. It's a natural boundary.
The Consumer should handle those error situations and decide the most appropriate what to communicate that. It may well choose to generate an exception. But these exceptions are disjoint from the original issue/eception that caused the service to return an error code.
Going further I would say #yahir is right in what he says also. HTTP service would expose HTTP errors, and it may well just be using another service underneath that returns another kind of errors, but it's job will be to handle or map them appropriately.
Ask yourself what other options do you have, sometimes exceptions are necessary. The only other thing you could do is return a status of failure or success and handle appropriately.
I'd say the service layer should behave just like any other method exposed to client code. After all, that's exactly what it is.
Clients that will use it through RPC, will expect exactly this behavior.
Other cilents, such as REST, should anyway access the services layer through some other wrapping layer (e.g. Controller layer). One of this wrapping layer duties is transforming the response to be client-consumable.