Unfortunately, this approach has some flaws. For one, it relies on developers remembering to duplicate validation features on both the client and server , which they often don’t. Even if you use a system that “automatically” applies validation logic in both places, there are cases where a page can’t be validated without checking with the server (validating the uniqueness of a user name comes to mind).
The approach on which we decided for the project I’m currently on leverages the ubiquity of server-side validation with much of the high level of responsiveness of client-side solutions.
Keep the client code clean
Say we’re building a sign-up form. We’ll need a “user name” field that we want to make sure unique within the system. Our HTML probably looks something like this:
We could perform this validation with a custom AJAX request (using jQuery, in this example):
Now we can check not only the “user name” field’s value, but all of the values of the form at once. The server’s response (which we’ll see how to build in the next section), could look something like this:
Instead of a simple “yes/no” validation response, we have a rich model representing exactly what’s wrong with the entire form, and with no additional markup (or even client-side code, beyond our single form hijacking call). We can even use the keys in this return object (which correspond to the
name values of form inputs) to highlight the erroneous fields:
Add the server component
In this project, built on ASP.NET MVC, we use the Fluent Validation library for validating data sent up from the client, though this approach hardly requires .NET. To get started, we’ll need a model class to store this form’s data:
We’ll also add a custom validator, using the Fluent Validation syntax. This example is relatively sparse, but the Fluent Validation API is quite flexible.
ASP.NET MVC already has a built-in server-side validation concept, called “Model State”, that Fluent Validation bolts onto. A
ModelState object contains a .NET object–based representation of exactly the server result we want, so all we need to do is respond to invalid requests with it. Another MVC extensibility point, “Action Filters”, gives us this ability:
In short, this filter serializes the
ModelState object and sends it down to the client as JSON with a “400” status code (“Bad Request”). .NET provides a
JsonResult object, but the default serializer misbehaves frequently with all but the simplest of objects to serialize. As a result, we’ve opted to use the Newtonsoft JSON library instead.
You’ll need to attach this filter to your MVC application—if that’s your server-side framework of choice. We’re using it as a global action filter.
Now that we’ve built a client that’s aware of potential form errors reported in a certain structure, and instructed the server to send down a meaningful model on invalid form submissions, all that’s left is to sit back and enjoy never having to write a client-side form validator again!