Tag Archives: @RequestBody

Spring 3.1 Server side validation for AJAX request using @Valid and @RequestBody

21 Feb

A recent task of mine was to implement server side validation on a REST Web app that saves all of it’s form data via an Ajax POST or PUT request. Many of the form fields in the app are dynamically created so a binding between the jsp form and the Model object could not be easily created.

A general Controller method (pre-validation)  looks like this:

@RequestMapping(value="/user", method = RequestMethod.POST)
@ResponseBody
public User createNewUser(@RequestBody User user) {
    // Logic goes here
}

Step 1: Import the relevant libraries into your app

You’ll need javax.validation and Hibernate Validator. I’ve used Maven to manage my dependencies.

<!-- Server-side Validation -->
<dependency>
    <groupId>javax.validation</groupId>
    <artifactId>validation-api</artifactId>
    <version>1.0.0.GA</version>
</dependency>
    <dependency>
    <groupId>org.hibernate</groupId>
    <artifactId>hibernate-validator</artifactId>
    <version>4.2.0.Final</version>
</dependency>

Step 2: Add the relevant validation rules to your DTO.

Validation rules or “constraints” can be added directly to the relevant field in the form of an annotation.

You can use both:

public class User {

    @NotBlank
    @Size(max = 50)
    private String firstName;

    @Size(max = 50)
    private String lastName;

    @Email
    private String emailAddress;
}

Step 3: Mark your Object as an item that requires validating

Mark the object that needs to be validated with the @Valid annotation in the Controller method signature.

@RequestMapping(value="/user", method = RequestMethod.POST)
@ResponseBody
public User createNewUser(@Valid @RequestBody User user, Model model ) {
    // Logic goes here
}

Now, at this point if you try to trigger server side validation you’ll get a http 400 error, and if you run your application in debug mode you will notice that the error occurs at the method signature of your Controller method. This is how Spring is handling the validation error by default. If you try and handle the validation error within the original Controller method requested, you won’t get the chance to.

So, onto the next step…

Step 4: Add an exception handler so you can add some smarts to redisplay the errors to your user

In this example code, I’ve chosen to use a Set to store the error messages because I don’t want duplicate messages to be returned. However, depending on your app and your current set up, you may choose to handle errors a different way.

@ExceptionHandler(MethodArgumentNotValidException.class)
@ResponseBody
public ValidationError handleValidationException(MethodArgumentNotValidExceptionexception) {
    Set<ValidationError> errors = new HashSet<ValidationError>();
    for (ObjectError er : exception.getBindingResult().getAllErrors()) {
        errors.add(new ValidationError(er.getObjectName(), er.getDefaultMessage()));
    }

    return new ValidationErrorResponse(errs);

}

Step 5: Display the error to your user

Now, you might want to get a bit more sophisticated with your errors, but at this point I am just happy to display the validation messages in one go.
I’m using jQuery to handle my Ajax requests.

Assuming the ValidationErrorResponse class has a field “errorMessages”

// Function that Makes Ajax call
function doesSomeStuff() {
    $.ajax({
        type: "POST",
        url: "some/url/in/your/app",
       // ... etc ...
        error: function(data) {
            if (data.errorMessages != null) {
                handleAjaxError(data);
                return;
            }
            // ... etc ...
        }
    });
}

// function that handles ajax error
function handleAjaxError(data) {
        var $errorMessageArea = $("#errorMessageArea");
        for(var i = 0; i < data.errorMessages.length; i++) {
            // append the current error message to the element on the web page
            $errorMessageArea.append($("<li />", { text: data.errorMessages[i] }));
        }
    }
}