19

I'm 100% on board with the case that one should definitely use both client-side and server-side data validations.

However, in the frameworks and environments I've worked in, the approaches I've seen have never been DRY. Most of the time there's no plan or pattern - validations are written in the model spec, and validations are written in the form on the view. (Note: Most of my first-hand experience is with Rails, Sinatra, and PHP w/ jQuery)

Mulling it over, it seems like it would not be difficult to create a generator which, given a set of validations (e.g. model name, field(s), condition), could produce both the necessary client-side and server-side material. Alternately, such a tool could take the server-side validations (such as the validates code in an ActiveRecord model) and generate client-side validations (such as jQuery plugins, which would then be applied to the form.

Obviously, the above is just a "hey I had this idea" musing, and not a formal proposal. This sort of thing is surely more difficult than it seemed when the idea hit me.

That brings me to the question: How would you approach designing a "write once, run on server and client" technique for data validation?

Related subtopics: Do tools like that exist for any particular frameworks or client-server technologies? What are major gotchas or challenges with trying to maintain only one set of validations?

4 Answers 4

6

In my limited experience, the points where validation are required are

  1. The presentation level using HTML,
  2. at the post-presentation level (i.e., Javascript validation),
  3. at the combination level where interactions between multiple fields have to be validated together,
  4. at the business logic level and
  5. at the database level.

Each of them have different languages, timings, and triggers. For instance, it makes little sense to validate a field before the entire record is in a consistent state, unless you want to validate just one piece. Constraints at the database level have to be applicable only at the end before a commit, and cannot readily be done piece-wise.

A related concept is that representing data varies between each of the levels. A simple example is a web browser represents a piece of text as, perhaps, CP1290, while the database represents it in UTF-8; the lengths of the two strings differ so enforcing length constraints gets awkward.

2
  • yup, different languages and frameworks make this impractical. Not "undoable" because with enough resources it could be done but writting auto converters to and between languages is a HUGE task. Doing it in a reasonable timeframe and then maintaining it as the relevant technologies change would be a lot of work. Jun 19, 2014 at 15:53
  • It's definitely true that many server-side validations (e.g. uniqueness of a field) cannot be performed in-browser. However, it's also true that any client-side validations need to be repeated in the server, since you can't trust the client. That's where I see DRYing things up being especially useful. For example, I could see a gem that extends Rails' form_for to automatically provide client-side validation code being very useful.
    – Dan
    Nov 24, 2017 at 23:46
5

One consideration that often limits solutions is the network round trip. The client is supposed to validate the user data without sending a message over the network. In other words, when the user hits the submit button, the client is supposed to validate the data locally.

First, let's assume that we do not have this limitation. We could communicate with a network endpoint that is good at articulating validation issues. For example, when you submit your new User record to it, rather than responding with a vanilla HTTP error code, it could return a detailed JSON response itemizing the issues and the client would smartly update the display to reflect the problems it encountered. The endpoint plays the role of a validation gateway.

It's DRY but not without drawbacks. First, it depends on the network roundtrip taxing our server with validations that could have been handled client side. Second, the design anticipates that all CRUD operations will occur via our endpoints, but what about when developers and processes bypass our data access layer by going directly against the database?

Let's revisit our solution to overcome these drawbacks. Instead let's store and communicate our validations as metadata:

{field: 'username', type: 'required'}
{field: 'username', type: 'unique'} //requires a network roundtrip
{field: 'password', type: 'length', min: 10, max: 50}
{field: 'password', type: 'contains', characters: ['upper', 'special', 'letter', 'number']}

Both the client and the server would have some mechanism (e.g. an engine) for interpreting and applying this data. (Some call this the free monad as it separates the declarative portion from its interpreter.) In JavaScript we could map each piece of information to working functions. To boot, we can teach any layer of our architecture, including our database, to enforce validations consistently.

5
  • How do you describe a field when a field is represented differently in web browser, transport, implementation language and database? For instance, the number of bytes required to represent a string field varies when using CP1290 (IE), UTF-8 (JSON), UTF-8 (C#), or UCS-16 (Oracle). What does a length constraint mean? More importantly for the browser, when the character representation depends on the browser and operating system? Jun 19, 2014 at 22:15
  • These constraints are aimed as a mental model at human beings. Your job as a programmer is to abstract away the differences to the machine so that the person doesn't have to care about any technical differences. Jun 20, 2014 at 11:59
  • You completely missed the point. So far, nobody has presented an abstraction that allows validation from end to end, with one specification. From the OP, "write once" implies that having different clauses that address different stages doesn't qualify. Similarly, I see nothing in your proposed validation that addresses interfield or interobject validation. Jun 20, 2014 at 14:06
  • Interfield/object validations are not much of a stretch. The metadata just represents the relationship. Write once implies that I an write a single validation once and have it enforced at multiple sites, which this does. You add metadata to a table. That metadata is received by any site and a simple class/utility/engine enforces the constraint. Jun 20, 2014 at 14:50
  • 1
    Such a validation language would be extremely useful. It could replace perhaps a third of the code involved with UI intensive web applications. Jun 20, 2014 at 15:37
2

One way would be to use same language / framework on both server and client side.

E.g.

Node.js :: Client / Server in JavaScript GET :: Client / Server in Java

In this case, most of the "Domain Object" code would be common, that would include validation. Framework will invoke the code as required. E.g. Same code would be invoked in browser before "submit" and on server side web service.

EDIT (June/2014) : With Java 8, is now easy to integrate JS validation code in Java Applications as well. Java 8 has a new JS execution engine that is more permanent (E.g: it makes use of invokeDynamic).

3
  • When it comes to the SQL database not sure how this would work. Jun 19, 2014 at 15:54
  • It also doesn't solve the issue that the browser and operating system affect the input domain. Jun 19, 2014 at 22:23
  • @Micheal Durrant, For Database validation are implemented as DB constraints (such as foreign key, unique etc). BobDalgleish, 1. Issue of browser/OS compatibility can be mitigated by using a Library that tweaks runtime according to Browser (such as Sencha) 2. Browser comatibility sually does not impact "logical" parts of code such as validation, compatibility issues are usually around DOM/UI Rendering. Jun 25, 2014 at 9:48
0

I was just thinking about the same problem. I was thinking of using ANTLR to get an abstract syntax tree in both C# and javascript. From there you use tree walkers to apply the actions specified in the language to the objects to be validated.

So then you could store a description of the required validation where ever you like - possibly in the database.

This is how I would approach the problem.

Not the answer you're looking for? Browse other questions tagged or ask your own question.