Introduction
Exception Handling in RESTful webservices is very interesting as well as important topic while writing RESTful web services.
Whenever any exception occurs in our web service, by default it will show error with HTTP error code with the description which user can’t understand easily.
Why one should handle Exceptions in Restful Web services?
User should understand if any error occurred in the system and he/she should easily understand what to do next so that error will not come again as most of the error are due to wrong input given by user and if sometimes error is due to our application he should clearly know that.
How to Handle Exceptions in Restful Web services?
In RESTful web services, usually response will be in JSON format. So, we need to create response object which will give error in JSON format.
Woooooh So let’s get hand dirty.
-------------------------------------------------------------------------------------------------
//ErrorResponse.java
package com.app.exception.mapper;public class ErrorResponse {
private long timestamp;
private int status;
private String error;
private String message;
private String path;
public String getError() {
return error;
}
public void setError(String error) {
this.error = error;
}
public long getTimestamp() {
return timestamp;
}
public void setTimestamp(long timestamp) {
this.timestamp = timestamp;
}
public int getStatus() {
return status;
}
public void setStatus(int status) {
this.status = status;
}
public String getMessage() {
return message;
}
public void setMessage(String message) {
this.message = message;
}
public String getPath() {
return path;
}
public void setPath(String path) {
this.path = path;
}
}
-------------------------------------------------------------------------------------------------
In above class, we created POJO class for ErrorResponse, where we are taking current timestamp to know that when the error occurred. The status to know what the status of error is.
Message is for error description and path to know about at what RESTful webservice the error came as we will develop lots of RESTful webservices. So, to understand where exactly error and it will easy to debug.
Now we will create ApplicationExceptionMapper to inject the error occurred in ErrorResponse object.
-------------------------------------------------------------------------------------------------
//ApplicationExceptionMapper.java
package com.app.exception.mapper;
import java.util.Date;
import javax.ws.rs.core.Context;
import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.Response;
import javax.ws.rs.core.Response.Status;
import javax.ws.rs.core.UriInfo;
import org.apache.commons.lang3.StringUtils;
public class ApplicationExceptionMapper {
@Context
private UriInfo uriInfo;
protected Response getErrorResponse(Exception e, Status statusCode, String error) {
final ErrorResponse errorResponse = new ErrorResponse();
errorResponse.setStatus(statusCode.getStatusCode());
errorResponse.setPath(uriInfo.getPath());
errorResponse.setTimestamp(new Date().getTime());
errorResponse.setError(error);
errorResponse.setMessage(null == e ? StringUtils.EMPTY : e.getMessage());
return Response.status(statusCode).entity(errorResponse).type(MediaType.APPLICATION_JSON_TYPE).build();
}
protected Response getErrorResponse(Status statusCode, String error) {
final ErrorResponse errorResponse = new ErrorResponse();
errorResponse.setStatus(statusCode.getStatusCode());
errorResponse.setPath(uriInfo.getPath());
errorResponse.setTimestamp(new Date().getTime());
errorResponse.setError(error);
errorResponse.setMessage("A problem has occurred please try again later");
return Response.status(statusCode). entity(errorResponse).type(MediaType.APPLICATION_JSON_TYPE).build();
}
}
-------------------------------------------------------------------------------------------------
Now we will make GenericExceptionMapper to map exception which did not match with any exceptions we handled and give error in proper format.
-------------------------------------------------------------------------------------------------
//GenericExceptionMapper.java
package com.app.exception.mapper;import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import javax.ws.rs.core.Response;
import javax.ws.rs.core.Response.Status;
import javax.ws.rs.ext.ExceptionMapper;
public class GenericExceptionMapper extends ApplicationExceptionMapper implements ExceptionMapper<RuntimeException> {
private static final Logger logger = LoggerFactory.getLogger(GenericExceptionMapper.class);
@Override
public Response toResponse(final RuntimeException e) {
logger.error("A RuntimeException occurred", e);
return getErrorResponse(Status.INTERNAL_SERVER_ERROR, "Internal Server Error");
}
}
-------------------------------------------------------------------------------------------------
We need to create WebApplicationExceptionMapper to catch WebApplicationException
-------------------------------------------------------------------------------------------------
//WebApplicationExceptionMapper.java
import javax.ws.rs.WebApplicationException;
import javax.ws.rs.core.Response;
import javax.ws.rs.core.Response.Status;
import javax.ws.rs.ext.ExceptionMapper;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/ * *
*
* Standard handler for any javax.ws.rs.WebApplicationException
*
*/
public class WebApplicationExceptionMapper extends ApplicationExceptionMapper implements ExceptionMapper<WebApplicationException> {
private static final Logger logger = LoggerFactory.getLogger(WebApplicationExceptionMapper.class);
@Override
public Response toResponse(final WebApplicationException wae){
logger.info("toResponse() - Returning a web exception to caller with status={}, message=\"{}\"", wae.getResponse().getStatusInfo().getStatusCode(), wae.getMessage(), wae);
return getErrorResponse(wae, Status.fromStatusCode(wae.getResponse().getStatus()), wae.getMessage());
}
}
-------------------------------------------------------------------------------------------------
Now there are some standard HTTP status code which used in web API. Here are some examples-
500 – InternalServerError
400 – BadRequest(IllegalArgumentException)
404 – Not Found
204 – No Content
201 – Resource created used for POST request
200 – OK etc.
more Http-status code information: https://httpstatuses.com/
To Handle 400 IllegalArgumentException, we need to create IllegalArgumentExceptionMapper
-------------------------------------------------------------------------------------------------
//IllegalArgumentExceptionMapper.java
package com.app.exception.mapper;
import javax.ws.rs.core.Response;
import javax.ws.rs.core.Response.Status;
import javax.ws.rs.ext.ExceptionMapper;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class IllegalArgumentExceptionMapper extends ApplicationExceptionMapper implements ExceptionMapper<IllegalArgumentException> {
private static final Logger logger = LoggerFactory.getLogger(IllegalArgumentExceptionMapper.class);
@Override
public Response toResponse(IllegalArgumentException exception) {
logger.info("Mapping IllegalArgumentException to {}, with message {}", Status.BAD_REQUEST.getStatusCode(), null == exception ? StringUtils.EMPTY : exception.getMessage());
return getErrorResponse(exception, Status.BAD_REQUEST, "Bad Request");
}
}
-------------------------------------------------------------------------------------------------
Same like IllegalArgumentExceptionMapper, you can create mapper for any HTTP status code.
Thank you …!!!
Comments
Post a Comment