I'm developing this Java RESTEASY application oriented to microservice pattern, i use methods like this to handle my exceptions:
#Path("/find/{id}")
#GET
#Produces(MediaType.APPLICATION_JSON)
public Response retrieveItemById(#PathParam("id") String id) {
int id;
try {
itemDTO result = service.getItem(id);
return Response.ok(result).build();
}catch(Exception e) {
return Response.status(404).build();
}
}
Somebody told me that this method to handle exception (in this case item not found exception) is wrong, but I can't figure out why.
What is the right way to handle exception such as item not found, creation failed, updated failed ... in a REST oriented application?
Thanks.
Related
I started to work with GraphQL for one week and I could not find out yet how to catch "internal" GraphQL errors like CoercingParseValueException. Because our Frontend use this endpoint to receive some information about shipping. When the schema or a required field is missing then GraphQL itself send an error which just got a message with arbitrary strings which you have to parse at the frontend to understand this message and show the client the correct error.
For our project, we defined a error-model for custom errors. This error-model contains a code field with a self defined code for every situtation like NotFoundException, ValidationException etc.
But how can I catch error from GraphQL and modify them?
Apporaches:
#Component
public class GraphQLErrorHandler implements graphql.servlet.GraphQLErrorHandler {
#Override
public List<GraphQLError> processErrors(List<GraphQLError> list) {
return list.stream().map(this::getNested).collect(Collectors.toList());
}
private GraphQLError getNested(GraphQLError error) {
if (error instanceof ExceptionWhileDataFetching) {
ExceptionWhileDataFetching exceptionError = (ExceptionWhileDataFetching) error;
if (exceptionError.getException() instanceof GraphQLError) {
return (GraphQLError) exceptionError.getException();
}
}
return error;
}
}
Does not work for me. ProcessErrors it is never called. I am using Spring Boot (Kickstarter Version)
For Custom errors I am using the new feature which was released for 10 days.
#Component("CLASSPATH TO THIS CLASS")
public class GraphQLExceptionHandler {
#ExceptionHandler({NotFoundException.class})
GraphQLError handleNotFoundException(NotFoundException e) {
return e;
}
#ExceptionHandler(ValidationException.class)
GraphQLError handleValidationException(ValidationException e) {
return e;
}
}
This approach works perfectly with custom error messages. To use this feature I have to enable the graphql-servlet property exception-handlers-enabled and set it to true. Nevertheless this approach does not catch "internal" Apollo/GraphQL errors even if the ExceptionHandler annotation is defined with Exception.class.
Maybe can help me with this problem?
Many thanks
try this. you should return ThrowableGraphQLError type for general exception
#ExceptionHandler(Exception::class)
fun handleException(e: Exception): ThrowableGraphQLError {
log.error("{}", e)
return ThrowableGraphQLError(e, "Internal Server Error")
}
I want to use Exception handling with the Restlet Framework and GWT clients.
The Restlet Framework supports the concept of annotated exceptions as described in this post;
http://restlet.com/company/blog/2015/12/21/exception-handling-with-restlet-framework/
In my project i created a LocationNameException
#Status(value = 409)
public class LocationNameException extends Exception
{
...
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
public LocationNameException(String pMessage, Throwable pCause)
{
super(pMessage, pCause);
}
}
And use this in my ServerResource;
#Override
#Transactional(rollbackOn = LocationNameException.class)
public LocationDto postLocation(LocationDto pLocationDto) throws LocationNameException
{
...
Location lLocation = new Location(pLocationDto);
try
{
LocationDao lLocationDao = getLocationDao();
lLocationDao.persist(lLocation);
}
catch (PersistenceException pPersistenceException)
{
throw new LocationNameException("Location requires unique Name", pPersistenceException);
}
...
return lLocationDto;
}
With the interface
public interface LocationListServerResourceInt
{
...
#Post
LocationDto postLocation(LocationDto pLocationDto) throws LocationNameException;
...
}
This works, in the case of an exception the call returns code 409;
And at the GWT client side onFailure() is called;
private class PostLocationCallback implements AsyncCallback<LocationDto>
{
...
#Override
public void onFailure(Throwable pCaught)
{
mCallback.onFailure(pCaught, mLocationDto);
}
}
But parameter pCaught only contains a ResourceException with the status code 409.
My LocationNameException isn't included in the underlying cause stack.
I need this LocationNameException for appropriate error message handling.
The reason is the generated ServerResourceProxy LocationListServerResourceProxyImpl by the Restlet GWT ClientProxyGenerator;
public void postLocation(LocationDto param1, final LocationDto> callback)
{
...
public void handle(Request request, Response response)
{
if (getClientResource().getStatus().isError())
{
callback.onFailure(new ResourceException(getClientResource().getStatus()));
}
else
{
...
}
I think i have to rewrite the Post method in the ClientProxyGenerator;
The LocationNameException is present in the Response data so the Basic approach using the getResponseEntity() method of the ClientResource class should be possible.
Is this the way to go? Or can i catch the LocationNameException exception somewhere else as suggested by Catching annotated exceptions?
It is really hard to try a different approach because of the generated code. Is there an easy way to circumvent the code generator with custom classes?
As already mentioned the LocationNameException is present in the Response data.
Therefore we can get it, just like a normal entity;
...
public void handle(Request request, Response response)
{
if (getClientResource().getStatus().isError())
{
LocationNameException lLocationNameException = null;
boolean serializationError = false;
try
{
if (response.isEntityAvailable())
{
if (MediaType.APPLICATION_JAVA_OBJECT_GWT.equals(response.getEntity().getMediaType()))
{
lLocationNameException = new ObjectRepresentation<LocationNameException>(
response.getEntity().getText(),
(SerializationStreamFactory) MyLocationListServerResourceProxyImpl.this, false)
.getObject();
}
else
{
throw new IOException("Can't parse the enclosed LocationNameException.");
}
}
}
catch (Throwable e)
{
serializationError = true;
callback.onFailure(new ResourceException(e));
}
if (!serializationError)
{
callback.onFailure(lLocationNameException);
}
}
else
{
...
The ClientProxyGenerator needs to know the exception type (in this case LocationNameException). Therefore we specify the exception in the ClientProxy interface;
#Post
void postLocation(LocationDto pLocationDto, AsyncCallback<LocationDto> pResult) throws LocationNameException;
And use getExceptionTypes() or getGenericExceptionTypes() in the ClientProxyGenerator;
Class<?>[] exceptionTypes = method.getExceptionTypes();
java.lang.reflect.Type[] genericExceptionTypes = method.getGenericExceptionTypes();
Of course not all REST methods use a custom exception. When getExceptionTypes() returns an empty list we just return the good old status code;
callback.onFailure(new ResourceException(getClientResource().getStatus()));
With help of Jerome Louvel and Thierry Boileau i created a new ClientProxyGenerator() that supports custom exceptions towards a GWT client;
Just specify the exception from the interface in the ServerResourceProxy (ClientProxy)
and voilĂ
It is possible to use this custom ClientProxyGenerator() in your project right away.
Download custom ClientProxyGenerator
And place it in a package on the server (for example package com.ludus.server.util)
In GWT module XML change the ClientProxyGenerator to the new version on the server;
And you're ready to go with your custom exceptions, but it would be nice if this extension would be integrated in the Restlet framework.
This question already has answers here:
How to handle REST Exceptions?
(2 answers)
Closed 7 years ago.
I would like to throw Exceptions from my REST endpoints. However, I am not too familiar with good REST design techniques. Consider the following...
//note the throws clause
#POST
public Response saveNewActivity(#HeaderParam("sessionTokenString") String sessionTokenString, Activity activity) throws Exception {
Activity result = as.saveNewActivity(activity);
if (result == null) {
throw new DuplicateDataException("blah blah blah");
}
return Response.ok(result).build();
}
versus handling Exceptions and explicitly returning only responses
#POST
public Response saveNewActivity(#HeaderParam("sessionTokenString") String sessionTokenString, Activity activity) {
try {
Activity result = as.saveNewActivity(activity);
if (result == null) {
throw new DuplicateDataException("blah blah blah");
}
return Response.ok(result).build();
} catch (Exception e) {
return Response.status(Response.Status.SOME_STATUS).build();
}
}
I can have the DuplicateDataException mapped using ExceptionMapper as follows
public class DuplicateDataExceptionMapper implements ExceptionMapper<DuplicateDataException> {
#Override
public Response toResponse(DuplicateDataException e) {
ErrorMessage errorMessage = new ErrorMessage ("Activity names must be unique.", <HttpStatusNumber>, "<add documentation here>");
return Response.status(Status.NOT_FOUND).entity(errorMessage).build();
}
}
Although in the end a Response gets returned anyways, but is one way of handling Exceptions (whether or not they are RuntimeExceptions) preferred over another, or does it not really matter? I have never seen a throws statement on a REST endpoint which is why I ask.
Please note that
this question or this question did not give the answer I am looking for.
If a parent class is catching the thrown exception and returning an appropriate HTTP Reponse error code (4xx), the initial code is fine.
If there's no parent class catching these to make them a 4xx instead of a 500, your code - to change the response code to something appropriate for this specific error - seems like a really good idea.
It is a bad idea to through an exception.
From the client perspective it results in an http 500 error code that don't tell nothing to an automatic program.
You should design your code trying to intercept all possible errors and reply with an appropriate error code inside your valid response. If your response in a json answer with something like the following:
{
statusCode: 345,
errorMessage: 'The error code message'
}
Leave the http status code 500 to unexpected errors.
I am developing the RESTful webservices using Jersey & Spring 3.2 along with Open CMIS.
I am not using MVC pattern of Spring and it's just Spring IOC & Jersey SpringServlet, the controller class is something like below code
#GET
#Path("/{objId:.+}")
#Produces(MediaType.APPLICATION_JSON)
#Consumes(MediaType.APPLICATION_JSON)
public statusMsg addObject(#PathParam("objId") String objId{
return repoService.addObject(objId);
}
In the repoService I am performing the business logic to add the object using CMIS, my question is that I am catching around 5 exceptions related to CMIS then the base exception i.e Exception but for every service method I have to repeat it which I don't want to do.
I was searching on Google and found that #ControllerAdvice is the best solution for such problem wheer you can define all the checked & unchecked exceptions and wherever remove all the try catch blocks from the application. But it only work with MVC pattern.
Question 1: Is there a way I can use this in above Jersey-Spring framework?
After more reserach I found that Jersey provides ExceptionMapper to handle customized exception but I want to catch more CMIS exception or default Exception or IO Exception etc.
Question 2: How can I do it with ExceptionMapper?
Question 3: Am I on the correct approach or do you suggest any better approach to handle such issues.
Thanks in advance.
I use jersey2.11 with Tomcat and almost exception handle with ExceptionMapper.
(In domain logic, only DB rollback process use try-catch code.)
I think ExceptionMapper with #Provider automatically choose correct ExceptionMapper. So I suppose this function is satisfied with "I want to catch more CMIS exception or default Exception or IO Exception etc."
This code is my handling ExceptionMapper design code.
1.Some Jersey Root Resource Class
#GET
#Produces("application/json")
public String getUser(#NotNull #QueryParam("id") String id,
#NotNull #QueryParam("token") String token) throws Exception { // This level throws exceptions handled by ExceptionMapper
someComplexMethod(id, token); // possible throw Exception, IOException or other exceptions.
return CLICHED_MESSAGE;
}
2.ExceptionMapper package. com.yourdomain.exceptionmapper
AbstractExceptionMapper.java (All ExceptionMapper class extends this Abstract class)
public abstract class AbstractExceptionMapper {
private static Logger logger = LogManager.getLogger(); // Example log4j2.
protected Response errorResponse(int status, ResponseEntity responseEntity) {
return customizeResponse(status, responseEntity);
}
protected Response errorResponse(int status, ResponseEntity responseEntity, Throwable t) {
logger.catching(t); // logging stack trace.
return customizeResponse(status, responseEntity);
}
private Response customizeResponse(int status, ResponseEntity responseEntity) {
return Response.status(status).entity(responseEntity).build();
}
}
ExceptionMapper.java (At least this mapper can catch any exception which is not define specify exception mapper.)
#Provider
public class ExceptionMapper extends AbstractExceptionMapper implements
javax.ws.rs.ext.ExceptionMapper<Exception> {
#Override
public Response toResponse(Exception e) {
// ResponseEntity class's Member Integer code, String message, Object data. For response format.
ResponseEntity re = new ResponseEntity(Code.ERROR_MISC);
return this.errorResponse(HttpStatus.INTERNAL_SERVER_ERROR_500, re, e);
}
}
WebApplicationExceptionMapper.java (Specify WebApplicationException)
#Provider
public class WebApplicationExceptionMapper extends AbstractExceptionMapper implements
ExceptionMapper<WebApplicationException> {
#Override
public Response toResponse(WebApplicationException e) {
ResponseEntity re = new ResponseEntity(Code.ERROR_WEB_APPLICATION);
return this.errorResponse(e.getResponse().getStatus(), re, e);
}
}
ConstraintViolationExceptionMapper.java (Specify Hibernate Validator ConstraintViolationException)
#Provider
public class ConstraintViolationExceptionMapper extends AbstractExceptionMapper implements
ExceptionMapper<ConstraintViolationException> {
#Override
public Response toResponse(ConstraintViolationException e) {
ResponseEntity re = new ResponseEntity(Code.ERROR_CONSTRAINT_VIOLATION);
List<Map<String, ?>> data = new ArrayList<>();
Map<String, String> errorMap;
for (final ConstraintViolation<?> error : e.getConstraintViolations()) {
errorMap = new HashMap<>();
errorMap.put("attribute", error.getPropertyPath().toString());
errorMap.put("message", error.getMessage());
data.add(errorMap);
}
re.setData(data);
return this.errorResponse(HttpStatus.INTERNAL_SERVER_ERROR_500, re, e);
}
}
.. and other specify exception can create ExceptionMapper classes.
In my experience, Exception Mapper is high level idea for focus to domain logic. It could drive out boring scattered try-catch block code from domain logic.
So I hope that you feel the "Yes i am" at Question 3 to resolve the problem at your environment.
you have not used try catch and throw anywhere across the application.
My code design use throws at method like this and this make to manage by ExceptionMapper classes.
public String getUser(#NotNull #QueryParam("id") String id,
#NotNull #QueryParam("token") String token) throws Exception
So in above approach I have created just 1 class for all the exceptions which I could expect and for any unknown exception the base Exception will be there to catch.
Now wherever in my application if any exception occurs it comes to the CentralControllerException and appropriate response with http status code is sent back.
Q.2. Do you foresee any issue in above approach.
I think if simple project or never update/modify project (project lifecycle short time), your one class exception mapper approach ok.
But ... i never take this approach. Simply, if need to manage more exception, this method become big and complex, and hard to read and maintain becoming.
In my policy, OOP should use pleomorphism strategy any level code(class plan, DI plan) and this approach some part aim to drive out if/switch block in code. And this idea make each method short code and simple, clear to "domain logic" and code become to resistant to modify.
So i create implements ExceptionMapper and delegate to DI which ExceptionMapper class manage to exception.
(So DI manage replace your single class If block manage which exception handling, this is typically refactoring approach similar Extract xxx http://refactoring.com/catalog/extractClass.html.
In our discussion case, single class and one method too busy, so extract each ExceptionMapper class approaching and DI call suitable class & method strategy.)
Btw, system processing result is same at present point. But if need to reduce future development cost ,should not took approach one class exception handling plan. Because if give up simply code and refactor status, project code is dead faster.
This is my idea and why this.
regards.
thanks for your reply. I can see you have created multiple classes based on the exception type and behaviour.
Q1. In your services method are you throwing any exception like
public void addObject(String objId) throws WebApplicationException{
}
or you have not used try catch and throw anywhere across the application.
Actually, I have tried something where in my web application I am not using try, catch and throws anywhere and in my CentralControllerException I have mentioned like below:
public class CentralControllerHandler implements ExceptionMapper<Exception> {
#Override
#Produces(MediaType.APPLICATION_JSON)
public Response toResponse(Exception ex) {
if(ex instanceof CmisContentAlreadyExistsException){
log.error(ex);
// send Response status as 400
}
if(ex instanceof IOException){
log.error(ex);
// send Response status as 400
}
return Response;
}
}
So in above approach I have created just 1 class for all the exceptions which I could expect and for any unknown exception the base Exception will be there to catch.
Now wherever in my application if any exception occurs it comes to the CentralControllerException and appropriate response with http status code is sent back.
Q.2. Do you foresee any issue in above approach.
I have the following code:
#POST
#Path("query")
#Produces(MediaType.APPLICATION_JSON)
public MyObject myMethod(#FormParam("id") String id)
{
//if some condition is met
if(...)
throw new WebApplicationException(Response.Status.SERVICE_UNAVAILABLE);
else
//proceed to my logic and return myObject
}
So basically, if my web client, using AJAX, receives a Response.Status.SERVICE_UNAVAILABLE, it will show a customized web page. If the call is successful, it will show a different web page.
My questions is: Is there anyway that in myMethod, I can return the Response.Status.SERVICE_UNAVAILABLE without throwing the exception. Something like:
if(...)
return Response.Status.SERVICE_UNAVAILABLE)
else
//proceed my logic and return myObject
I basically want the client to know that its request cannot be fulfilled at this time and show a customized web page.
Your method should return a Response, instead of MyObject:
#POST
#Path("query")
#Produces(MediaType.APPLICATION_JSON)
public Response myMethod(#FormParam("id") String id) {
if (/* error */) {
return Response.status(Response.Status.SERVICE_UNAVAILABLE).build();
}
return Response.ok().entity(new MyObject(/* ... */)).build();
}
However, I would strongly recommend to use WebApplicationException for such situations, mostly for the sake of logical separation of regular and exceptional cases. This SERVICE_UNAVAILABLE response status (HTTP code 503) is a clear indicator of error, not a normal execution flow.