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)'.
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.
I'm wondering if there is any elegant way to catch all exceptions (specifically custom runtime exceptions) and return an exception containing a list of the messages.
Instead of having a String message, the big exception would then contain String[] message for example.
Scenario:
A REST request is made to the back-end with a JSON object containing a bunch of fields. I want to validate these fields on the backend and return a list of errors if any exceptions occur.
If both the name and lastname field are not acceptable input, I don't want to throw an exception on the invalid name and have the user change the name and submit again only to get an error message that the lastname is invalid too.
Hence why I want to collect all invalid input and return a list of these in the form of an exception.
Spring collects JSR-303/JSR-349 bean validation failures into a BindException:
Thrown when binding errors are considered fatal. Implements the BindingResult interface (and its super-interface Errors) to allow for the direct analysis of binding errors.
Instead of developing your own mechanism for bean validation you might want to read 3. Validation, Data Binding, and Type Conversion and follow the standards.
With Spring Boot, you can use the following annotation to handle any kind of Exception for a class or a method :
#ExceptionHandler(YourExceptionHandler.class)
And you can create a class that let you regroup all your custom exception management like this (if you want to gather it) :
#ControllerAdvice
class GlobalControllerExceptionHandler {
#ResponseStatus(HttpStatus.CONFLICT) // 409
#ExceptionHandler(DataIntegrityViolationException.class)
public void handleConflict() {
// Nothing to do
}
}
You can also implement the interface HandlerExceptionResolver to manage all Exceptions that ARE NOT handled by the Controllers (all the others runtime Exceptions)
public interface HandlerExceptionResolver {
ModelAndView resolveException(HttpServletRequest request,
HttpServletResponse response, Object handler, Exception ex);
}
Everything is explained in details here : https://spring.io/blog/2013/11/01/exception-handling-in-spring-mvc
EDIT: I just read that you added up scenario. Actually, for your special case, you should just parse the object, and return one exception (like bad object format, along with a 400 HTTP status code error, with a custom message containing all the fields that are invalid. I guess.
I am using Play framework (2.5) for Java development. In that, we configure routes and for those routes the relative controller methods to be triggered.
I have a question whether is it OK to include exception throws in these controller method signatures or we must catch them inside the method body?
EX:
public Result getPurchasedStatisticsOutOfAllPriceChecked(String from, String to) throws InvalidParameterException, SalesServiceException {
RequestParams requestParams = new RequestParams(messageProvider);
requestParams.setDateRangeStart(from);
requestParams.setDateRangeEnd(to);
return ok(processInfluenceOnSales(influenceOnOverallSales));
}
I think the better way is to handle those Exceptions inside your Action method, instead of throwing. By this you can respond to the client with relevant error message, otherwise you end up with
500 Internal server error
and your stacktrace looks like following play.api.http.HttpErrorHandlerExceptions$$anon$1: Execution exception followed by respective exception trace.
I have a simple POJO that I annotated with REST annotations as follows:
#GET
#Path("/domains/{domainid}")
#Override
public Domain getDomain(#PathParam("domainid") UUID domainID) throws Exception {
logger.info("Retrieving domain "+ domainID);
Domain d = null;
try {
d = MyClient.getDomains().get(domainID.toString());
logger.debug("Returning "+d.getName());
} catch (Exception e) {
logger.error("Could not retrieve domain", e);
}
return d;
}
Note that the log statement including d.getName() can actually throw an NPE which is then caught and logged. That's not pretty but it's also not the point here.
Ultimately whether d has a value or not, I return it.
In the case of a null value, my client receives an HTTP 204 status code. This is what wget displays: HTTP request sent, awaiting response... 204 No Content
Oddly enough, my browsers don't budge an inch. They still display the previous page (I suppose it makes sense to stay put when no content is received). I would have expected a blank page.
Three questions:
is HTTP 204 the right response to be returned?
how can I control that via annotations? Via other configuration?
what is the standard REST best practice regarding null objects?
Thanks
EDIT
There is a great question on the very same topic here: Is it correct to return 404 when a REST resource is not found?
If the request is trying to GET/locate/find a resource, and it can't be found, traditionally, we should send a 404 Not Found. For further discussion see here.
That being said, I generally like to have my resource methods return Response, as it's easier to fine tune the response the way I want (a little - not much - more detail here). But seeing as how your method is overriding an interface contract (and returning a model object), JAX-RS gives us a nice hierarchy of exceptions that will get mapped to a particular response/status. The list can be seen here.
So in your particular case, if the resource can't be found, you can throw a WebApplicationException(Response.Status.NOT_FOUND) or a NotFoundException, and the exception will be mapped to a 404 Not Found. Something like
d = MyClient.getDomains().get(domainID.toString());
if (d == null) {
throw new NotFoundException(); // <-- JAX-RS 2.0
// or throw new WebApplicationException(Response.Status.NOT_FOUND);
// ^^ JAX-RS 1.x
}
The method will exit when the exception is thrown, and the client will receive a response with a 404 Not Found status.
Related Q&As
How to catch 404 (NotFoundException) without being dependant on a JAX-RS implementation?
Is it correct to return 404 when a REST resource is not found?
EDIT
In the first line I stated "If the request is trying to GET/locate/find a resource..", but really, this applies to almost all cases we are using URI templates, whether it is for a GET, POST, PUT, DELETE, whatever. Consider this example
#PUT
#Path("/customers/{id}")
public Response updateCustomer(#PathParam("id") long id, Customer customer) {
...
}
Here is a method that allows the client to update a customer via a PUT. The client should know the complete URI to the resource before trying to update it. If the {id} parameter (used for lookup) is not found say in a database, then the resource doesn't exist, and a 404 Not Found should also be returned to the client.
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