Search code examples
spring-bootresthttp-status-codes

Customizing HttpStatus code to column cannot be null


What is the best HttpStatus code to return on a Rest Api when I have java.sql.SQLIntegrityConstraintViolationException: Column 'xpto' cannot be null?

I have an exception handler to other types, but not to null fields:

@ExceptionHandler({DataIntegrityViolationException.class})
protected ResponseEntity<Object> handleDataIntegrityViolation(DataIntegrityViolationException ex, WebRequest request) {
        Throwable cause = ex.getRootCause();
        if (cause instanceof SQLIntegrityConstraintViolationException) {
            SQLIntegrityConstraintViolationException consEx = (SQLIntegrityConstraintViolationException)cause;
            String message = "";
            String constraint = "";
            HttpStatus httpStatus = null;
            if (consEx.getMessage().contains("UNIQUE")) {
                message = "Cannot enter the same record twice";
                constraint = "DUPLICATED_RECORD";
                httpStatus = HttpStatus.CONFLICT;
            } else if (consEx.getMessage().contains("foreign key constraint")) {
                message = "Record still have reference from other table";
                constraint = "USED_RECORD";
                httpStatus = HttpStatus.UNPROCESSABLE_ENTITY;
            }

            return this.buildResponseEntity(new ApiError(httpStatus, message, consEx.getMessage(), constraint));
        } else {
            return ex.getCause() instanceof org.hibernate.exception.ConstraintViolationException ? this.buildResponseEntity(new ApiError(HttpStatus.CONFLICT, "Database error", ex)) : this.buildResponseEntity(new ApiError(HttpStatus.INTERNAL_SERVER_ERROR, ex));
        }
}

Solution

  • I've added a treatment to column cannot be null and used 400 - BAD_REQUEST as http status code:

        @ExceptionHandler(DataIntegrityViolationException.class)
        protected ResponseEntity<Object> handleDataIntegrityViolation(DataIntegrityViolationException ex,
                                                                      WebRequest request) {
            Throwable cause = ex.getRootCause();
            if (cause instanceof SQLIntegrityConstraintViolationException) {
                SQLIntegrityConstraintViolationException consEx = (SQLIntegrityConstraintViolationException) cause;
                String message = "";
                String constraint = "";
                HttpStatus httpStatus = null;
                if (consEx.getMessage().contains("UNIQUE")) {
                    message = "Cannot enter the same record twice";
                    constraint = "DUPLICATED_RECORD";
                    httpStatus = HttpStatus.CONFLICT;
                } else if (consEx.getMessage().contains("foreign key constraint")) {
                    message = "Record still have reference from other table";
                    constraint = "USED_RECORD";
                    httpStatus = HttpStatus.UNPROCESSABLE_ENTITY;
                } else if (consEx.getMessage().contains("cannot be null")){
                    message = "Record cannot be null";
                    constraint = "NULL_RECORD";
                    httpStatus = BAD_REQUEST;
                }
                return buildResponseEntity(new ApiError(httpStatus, message, consEx.getMessage(), constraint));
            } else if (ex.getCause() instanceof ConstraintViolationException) {
                return buildResponseEntity(new ApiError(HttpStatus.CONFLICT, "Database error", ex));
            }
            return buildResponseEntity(new ApiError(HttpStatus.INTERNAL_SERVER_ERROR, ex));
    }