WebApplicationException
In Java REST you can throw a WebApplicationException, which indicates that something went wrong. You can add the HTTP Status to the exception, to indicate what went wrong.throw new WebApplicationException(Response.Status.BAD_REQUEST);
But that amount of information is in most cases too little. Sure, a HTTP Status of 404 (Not Found) is quite clear, but you'd like some more information.Luckily, I found out that we can add an entity in the Response and add the Response to the WebApplicationException.
In fact, it is the most convenient to just create your own subclass of WebApplicationException to handle this automatically.
Your own WebApplicationException
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import javax.ws.rs.WebApplicationException; | |
import javax.ws.rs.core.Response; | |
/** | |
* | |
* @author mr.bear | |
*/ | |
public class MudWebException extends WebApplicationException | |
{ | |
/** | |
* Create a new MudWebException. | |
* | |
* @param name the name of the player. | |
* @param message the message to send to the player. | |
* @param status the HTTP status code. | |
*/ | |
public MudWebException(String name, String message, Response.Status status) | |
{ | |
super(message, (new ErrorDetails(name, message)).getResponse(status)); | |
} | |
/** | |
* Create a new MudWebException. | |
* | |
* @param name the name of the player. | |
* @param message the message to send to the player. | |
* @param status the HTTP status code. | |
* @param errormessage the error message to log in GlassFish (which can provide additional information too sensitive for the user). | |
*/ | |
public MudWebException(String name, String message, String errormessage, Response.Status status) | |
{ | |
super(errormessage, (new ErrorDetails(name, message)).getResponse(status)); | |
} | |
/** | |
* Create a new MudWebException caused by a different exception. | |
* | |
* @param name the name of the player. | |
* @param message the message to send to the player. | |
* @param status the HTTP status code. | |
* @param e the underlying exception that was thrown. | |
*/ | |
public MudWebException(String name, String message, Throwable e, Response.Status status) | |
{ | |
super(e, (new ErrorDetails(name, message, e)).getResponse(status)); | |
} | |
/** | |
* Create a new MudWebException caused by a different exception. | |
* | |
* @param name the name of the player. | |
* @param status the HTTP status code. | |
* @param e the underlying exception that was thrown. | |
*/ | |
public MudWebException(String name, Throwable e, Response.Status status) | |
{ | |
super(e, (new ErrorDetails(name, e)).getResponse(status)); | |
} | |
/** | |
* Create a new MudWebException caused by a different exception. | |
* | |
* @param status the HTTP status code. | |
* @param e the underlying exception that was thrown. | |
*/ | |
public MudWebException(Throwable e, Response.Status status) | |
{ | |
super(e, (new ErrorDetails(e)).getResponse(status)); | |
} | |
} |
An Error Entity
The entity that gets translated into JSON and passed over the line, in my case called ErrorDetails, can provide all the information you need.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import java.io.PrintWriter; | |
import java.io.StringWriter; | |
import java.util.Date; | |
import javax.ws.rs.core.Response; | |
import javax.xml.bind.annotation.XmlRootElement; | |
/** | |
* Object that is sent to the client as a json string, upon throwing | |
* a MudWebException. | |
* | |
* @see MudWebException | |
* @author mr.bear | |
*/ | |
@XmlRootElement | |
public class ErrorDetails | |
{ | |
public Date timestamp; | |
public String errormessage; | |
public String stacktrace; | |
public String user; | |
public ErrorDetails() | |
{ | |
// required for REST | |
} | |
ErrorDetails(String errormessage) | |
{ | |
this.timestamp = new Date(); | |
this.errormessage = errormessage; | |
} | |
ErrorDetails(String user, String errormessage) | |
{ | |
this(errormessage); | |
this.user = user; | |
} | |
ErrorDetails(Throwable t) | |
{ | |
this.timestamp = new Date(); | |
this.errormessage = t.getMessage(); | |
this.stacktrace = stackTraceToString(t); | |
} | |
ErrorDetails(String user, Throwable t) | |
{ | |
this(t); | |
this.user = user; | |
} | |
ErrorDetails(String user, String message, Throwable t) | |
{ | |
this(t); | |
this.user = user; | |
this.errormessage = message; | |
} | |
private String stackTraceToString(Throwable e) | |
{ | |
StringWriter sw = new StringWriter(); | |
PrintWriter pw = new PrintWriter(sw); | |
e.printStackTrace(pw); | |
return sw.toString(); | |
} | |
public Response getResponse(Response.Status status) | |
{ | |
return Response.status(status).entity(this).build(); | |
} | |
} |
The getResponse method is the one that creates the Response, which is used to provide the HTTP Status code and the error payload for the WebApplicationException.
The json generated looks like:
{
timestamp="2014-09-21T21:34:01.831",
errormessage="sdsgsdgsgd was not found.",
stacktrace=””,
user="sdsgsdgsgd"
}
timestamp="2014-09-21T21:34:01.831",
errormessage="sdsgsdgsgd was not found.",
stacktrace=””,
user="sdsgsdgsgd"
}
JQuery
It just took a little effort to retrieve the ErrorDetail object from the Xqhr object in the JQuery Ajax call. This should be done during error processing, as shown in the JQuery Ajax call below.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
$.ajax({ | |
type: 'POST', | |
url: some_url // Which url should be handle the ajax request. | |
cache: false, | |
success: (function(data) {processor(data); }), | |
error: webError, | |
complete: (function() { if (window.console) console.log("complete"); }), | |
dataType: 'json', //define the type of data that is going to get back from the server | |
contentType: 'text/plain; charset=utf-8', | |
data: command | |
}); // end of ajax |
The webError in the code above is a function to parse the JSON containing ErrorDetails object, provided below.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
function webError(jqXHR, textStatus, errorThrown) | |
{ | |
if (window.console) | |
{ | |
console.log(jqXHR); | |
console.log(textStatus); | |
console.log(errorThrown); | |
} | |
try | |
{ | |
var errorDetails = JSON.parse(jqXHR.responseText); | |
if (window.console) console.log(errorDetails); | |
} catch(e) | |
{ | |
alert("An error occurred."); | |
if (window.console) console.log(e); | |
return; | |
} | |
if (errorDetails.stacktrace !== undefined) | |
{ | |
var buffer = "Timestamp: " + errorDetails.timestamp + "<br/>"; | |
buffer += "Errormessage: " + errorDetails.errormessage + "<br/>"; | |
buffer += "Stacktrace: " + errorDetails.stacktrace + "<br/>"; | |
buffer += "User: " + errorDetails.user + "<br/>"; | |
buffer += "Browser CodeName: " + navigator.appCodeName + "<br/>"; | |
buffer += "Browser Name: " + navigator.appName + "<br/>"; | |
buffer += "Browser Version: " + navigator.appVersion + "<br/>"; | |
buffer += "Cookies Enabled: " + navigator.cookieEnabled + "<br/>"; | |
buffer += "Platform: " + navigator.platform + "<br/>"; | |
buffer += "User-agent header: " + navigator.userAgent + "<br/>"; | |
var $ = Karchan.$; | |
$("#warning").html(buffer); | |
} | |
alert(errorDetails.errormessage); | |
} |
It parses the jqXHR.responseText, to be precise. And if a stacktrace is provided, the details are put into a HTML tag with id "warning". An 'alert' is always provided.
References
- Whatever can go wrong … Error Handling and RESTful Services
- http://djna.wordpress.com/2009/12/07/whatever-can-go-wrong-error-handling-and-restful-services/
- RESTful API Design: what about errors?
- https://blog.apigee.com/detail/restful_api_design_what_about_errors
- How to get the jQuery $.ajax error response text?
- http://stackoverflow.com/questions/1637019/how-to-get-the-jquery-ajax-error-response-text
- Use jQuery to catch and display ASP.NET AJAX service errors
- http://encosia.com/use-jquery-to-catch-and-display-aspnet-ajax-service-errors/
thank's for sharing
ReplyDelete