Over a million developers have joined DZone.
{{announcement.body}}
{{announcement.title}}

Implementing Error Handling in Restful Web-services

DZone's Guide to

Implementing Error Handling in Restful Web-services

· Integration Zone
Free Resource

Share, secure, distribute, control, and monetize your APIs with the platform built with performance, time-to-value, and growth in mind. Free 90-day trial of 3Scale by Red Hat

Implementing Error Handling in Restful Web-services:

From Restful Web-Services (here afer referred to as services) perspective, errors can be classified in two broad categories—User errors and System errors. User errors pertain to validation errors for data entered by the users and system errors pertain to services failures due to coding errors or data-source un-availability or other causes. Here is an example implementation:

  • Create an Exception SystemException. SystemException contains an enum of all possible SystemError(s) in the service. SystemError in turn contains HttpStatusCode and Error message for that error. 
public class SystemException extends RuntimeException{
    private SystemError error;
    private String message;


    public SystemException(SystemError error){
        super();
        this.error = error;
    }

    public SystemException(SystemError error, String message){
        super();
        this.message = message;
        this.error = error;
    }

    public SystemError getError(){
        return error;
    }

    public enum SystemError{
        SQL_ERROR(500, "Internal Server Error");
        private int code;
        private String message;
        private SystemError(int code, String message){
            this.code = code;
            this.message = message;

        }
        public int getCode(){
            return code;
        }

        public String getMessage(){
            return message;
        }
    }

    public String getMessage(){
        return message != null?message:error.message;
    }

    public int getCode(){
        return error.code;
    }
}
  • Create an Exception UserException. UserException contains an enum of all possible UserError(s) in the service. UserError in turn contains HttpStatusCode and Error message for that error. UserException also contans list of error messges that can be shown to the user.
public class UserException extends RuntimeException{

    private List<String> errors;
    private UserError error;

    public UserException(UserError userError, List<String> errors){
        super();
        this.errors = errors;
        this.error= userError;
    }

    public List<String> getErrors(){
        return errors;
    }

    public UserError getError(){
        return error;
    }

    public enum UserError{
        USER_DATA_VALIDATION_ERROR(450, "User data validation failed");
        private int code;
        private String message;
        private UserError(int code, String message){
            this.code = code;
            this.message = message;
        }
    }

    public String getMessage(){
        return error.message;
    }

    public int getCode(){
        return error.code;
    }
}
  • Create an Exception Mapper that maps exceptions to the service-Response (example uses JBoss jax-rs implementation). Code from exception is set as HTTP Status Code and exception message(that has contextual information about the error) is used to set 'ERROR_DETAIL' esponse header. In case of user errors, list of error messages is included in the response body that can be shown to the user. All exceptions other than UserException and SystemException are mapped to internal server error (code 500).

@Provider

public class MyExceptionMapper implements ExceptionMapper<Exception>{

 

@Override

public Response toResponse(Exception exception){

 

Response.ResponseBuilder rb =

if (exception instanceof UserException || exception instanceof SystemException){

rb=Response.status(exception.getCode());

rb.header("ERROR_DETAIL", exception.getMesage());

if (exception instanceof UserDataValidationException) {

           Object entity = new GenericEntity<List<String>>(((UserDataValidationException)exception).getErrors()) {};

rb.entity(entity);

}

} else rb=Response.status(500);

return rb.build();

}

 

  •   For System failure, service code should throws SystemException: 
throw new SystemException(SystemError.SQL_ERROR, "your optional message to overide the one in enum if needed");

 

  • For user error, service code should throws UserException:    

throw new UserException(UserError.SQL_ERROR, yourErrorMessagesList);

 

That should be all that that should be needed for Erorr handling in the services.  Http Status codes in the UserException and SystemException for most part should be  Standard Http Status codes. For rare appliation specific needs, additional custom HTTP response codes can be included but they should conform to HTTP guidelines. 

Explore the core elements of owning an API strategy and best practices for effective API programs. Download the API Owner's Manual, brought to you by 3Scale by Red Hat

Topics:

Opinions expressed by DZone contributors are their own.

{{ parent.title || parent.header.title}}

{{ parent.tldr }}

{{ parent.urlSource.name }}