REST service: The proper way of returning exception

后端 未结 3 1118
太阳男子
太阳男子 2021-02-05 20:23

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 obj

相关标签:
3条回答
  • 2021-02-05 20:57

    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"
        }
    }]
    

    }

    0 讨论(0)
  • 2021-02-05 21:02

    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

    0 讨论(0)
  • 2021-02-05 21:03

    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

    0 讨论(0)
提交回复
热议问题