12

I use Jersey API for my REST service. My question is: Is there a more elegant way of returning exceptions in a JSON form? Is it better to concern myself with creating a json object myself and attaching it to the response directly?

This is a simplified example of one of the methods in the service. As you see, I use HashMap only because the method may throw an exception, in which case I need to return information about It.

@Path("/admin") public class AdminService { @Context HttpServletRequest request; @POST @Produces(MediaType.APPLICATION_JSON) public Map<Integer, String> createCompany(Company company){ Map<Integer, String> map = new HashMap<>(); try{ AdminFacade adminFacade = (AdminFacade)Utility.getFacade(request); adminFacade.createCompany(company); map.put(1,"success"); } catch (ExceptionREST e) { map.put(e.getErrorNumber(), e.getMessage()); } finally { return map; } } } 
4
  • what is wrong with what you have now? Commented Feb 26, 2016 at 1:09
  • 2
    Also, look at the following links: RESTful API Design, rest error handling Commented Feb 26, 2016 at 1:11
  • Nothing is wrong. I ask about writing conventions. This is something that I've invented but I'm sure that there's some convention about It, since I'm not the first one doing that. Commented Feb 26, 2016 at 1:12
  • you should be returning your error as an HTTP status code, with an (optional) expalanation in the body. as @arsham said, read about and understand the concepts of REST apis Commented Feb 26, 2016 at 1:26

3 Answers 3

17

You can create a class like the one below to represent an error,

@JsonPropertyOrder({ "code", "field", "message" }) public class ErrorInfo { private String code; private String field; private String message; public String getCode() { return code; } public void setCode(String code) { this.code = code; } public String getField() { return field; } public void setField(String field) { this.field = field; } public String getMessage() { return message; } public void setMessage(String message) { this.message = message; } } 

You can create a class which extends an exception like this,

public class InvalidInputException extends RuntimeException { private static final long serialVersionUID = -5027121014723838738L; private List<ErrorInfo> errors; public List<ErrorInfo> getErrors() { return this.errors; } public InvalidInputException(List<ErrorInfo> errors) { super(); this.errors = errors; } public InvalidInputException(String message, List<ErrorInfo> errors) { super(message); this.errors = errors; } } 

And have a exception mapper, where you can convert the List to json and return to the user with http status code 400 (Bad Request).

@Provider public class InvalidInputExceptionMapper implements ExceptionMapper<InvalidInputException> { @Override @Produces(MediaType.APPLICATION_JSON) public Response toResponse(InvalidInputException e) { ResponseBuilder rb = Response.status(Status.BAD_REQUEST); rb.entity(e.getErrors()); return rb.build(); } } 

Http Response will be,

HTTP/1.1 400 BAD REQUEST { "errors": [{ "error": { "code": "100", "field": null, "message": "Name is required" }, "error": { "code": "100", "field": null, "message": "Age is required" } }] 

}

Sign up to request clarification or add additional context in comments.

1 Comment

Thanks! that's what I did eventually.
2

I believe it is quite popular that people use http response status code to handle the error. E.g. 404 status is not found 5xx is server internal error e.t.c. You can easily set the error code by using the Response object. Instead of returning a map, return a Response object.

@Path("/admin")public class AdminService { @Context HttpServletRequest request; @POST @Produces(MediaType.APPLICATION_JSON) public Response createCompany(Company company){ Map<Integer, String> map = new HashMap<>(); try{ AdminFacade adminFacade = (AdminFacade)Utility.getFacade(request); Company commpany=adminFacade.createCompany(company);//this entity annotated by XmlRootElement Response response=Response.ok().entity(company).build(); } catch (ExceptionREST e) { response=Response.status(404).build(); } return response; }} 

To make the Restful api more robust, some will return an OK response to prevent "smart redirect" from the server and output some weird html. you can refer here for a list of http status code and what it mean. For Java EE Response class, you can refer the official javadoc

1 Comment

You have to declare the Response variable globally.
1

You can wrap your error into a class, say I have an ErrorData class which has status, message and stacktrace. Everytime an exception occurs, I throw a GeneralAppException with the errordata object.

public class GeneralAppException extends WebApplicationException { public GeneralAppException(ErrorData er) { super(Response.status(er.getStatusCode()). entity(er).type(MediaType.APPLICATION_JSON).build()); } } 

I have another class which has all the known errors, eg.

public static final ErrorData NODATAFOUND = new ErrorData(Response.Status.NOT_FOUND.getStatusCode(),"No data was found for given query"); public static final ErrorData CODEERROR = new ErrorData(502,"CodeError"); 

Your catch can look like

catch (ExceptionREST e) { throw new GeneralAppException(ErrorData.NODATAFOUND); } 

Reference used : https://jersey.java.net/documentation/latest/representations.html#d0e6665

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.