User Input Validation - ColdBox Series Part 9a

I decided to start a new sub-series on Validation, since it is a huge and controversial subject, I suspect it will take a post or two, or three.

So, I was chatting with Peter Farrell some time ago:

me: Peter, I have a quick question for you

Peter: Sure, what?

me: Where should input validation go? In the Controller or In the service layer?

Peter: THAT is NOT a quick question.

Those are not Peter's exact words. I do not have the transcript, but that is roughly how the conversation went.

So after learning more, talking to experts, asking questions and trying things out, I have come to the conclusion that Peter was right.

Handling Validation

There are A LOT of ways to handle user input validation. To name a few:

  • In the Controller
  • In the service layer
  • In the business object itself
  • In a separate validator object
  • With Javascript in the view

Now, I am not saying that any one way is the "right" way. I'm still not even sure which way is right for me. I am going to show you how I do it. I would love to hear feedback on this method. I am going to simplify some things just to keep my posts shorter.

Right now, the way I am handling validation is in the business object. I am not sure if that makes my bean "smart" or not. But it is self-validating, and I think that is kinda smart of it ;).

We have been working on creating Lists in our To-do list application. We have been able to populate a bean and get it persisted to the database, but we have not validated any of the input. In fact, right now, it will allow us to create a list with no name (or with duplicate names) and no priority, and it would let us pass in a non-numeric character into the priority if we intercept the form and alter the field. So this is all bad and can cause us errors and headaches down the line.

So what validation rules do we need?

  1. The list name cannot be empty
  2. The list name must be unique
  3. Priority must not be empty
  4. Priority must be numeric
  5. Priority must be 1, 2, or 3

In my next post, we will actually build this functionality, along with some supporting functionality into the bean and a bean decorator.

Comments
Francois Levesque's Gravatar Looking forward to your ideas on this. I'm happy to see I'm not the only one that thinks validation isn't as simple as it seems.
# Posted By Francois Levesque | 11/25/08 5:03 AM
Brian Swartzfager's Gravatar I'll be keeping an eye on this thread as well. Currently I'm in the "separate validation object" camp, but that's only because that's how I currently do validation. :)

Not to get ahead of the thread too much, but I don't see bean-based validation as a 100% solution because not everything on a web form necessarily maps to a bean property: sometimes a form value is required to determine a course of action rather than a piece of data, some value that must be valid but is not persisted in a bean or the database.
# Posted By Brian Swartzfager | 11/25/08 6:34 AM
Jason Dean's Gravatar @Brian, that is a good point, and one that I have yet to come across is my brief experience with this type of development. I am not sure of how to address that. My first instinct would be that it would be handled in the controller since something like that is more application specific. Since it is, as you said, not persisted or stored in the model, it seems the only other possible place for it is in the controller.

So you're right, 100% bean validation is not likely going to solve all of our problems. Of course, that's probably the case with everything. I'm still up in the air about which validation method is best for me. The validator object is intriguing, but I have yet to see an example of how this is done. I could probably figure it out, but to see a blog post about it would be great.

Come to think of it, I forgot to mention ValidateThis! as an option as well. I am not sure if it falls into the Validator Object category or into a category of its own. I need to look into that.
# Posted By Jason Dean | 11/25/08 8:06 AM
Luis Majano's Gravatar There are so many ways to do this Jason, like you have found out. I have used almost all of them and I have found a preference to do my validations by a separate validator. Why? Well, because the domain object itself (in my opinion) should not be concerned on how it validates its state, but that it has a state with data. The purpose of the business object's validation concerns cross boundaries with the concerns of the business rules. Therefore, I have found an approach where my validation is done before population, if it validates, then I populate my domain model object.

On this principle, we are building the validator plugin on ColdBox, that will be used to create validation rules and validation objects. Anyways, please go ahead and try all approaches!! Great post!!
# Posted By Luis Majano | 11/25/08 1:44 PM
Jason Dean's Gravatar So, I guess, my questions about the validator object are these:

Does the validator object get injected into the bean?
How does every bean get it's own custom validator object?
How does the validator object "learn" the rules? From metadata? From a config file?

Thank you everyone for your input. I am glad I released this short post before going into this further.
# Posted By Jason Dean | 11/25/08 2:25 PM
Bob Silverberg's Gravatar I like where you're going with this Jason, and you've already got come interesting suggestions in the comments. I very much like being able to ask my Business Object (BO) to validate itself, but i don't want it to actually know _how_ to validate itself, so I inject a Validator Object (VO) into the BO (using a factory). That allows me to call validate() on the BO, but all the BO does is turn around and call validate() on the VO. It gives me the API I want, but keeps things encapsulated. When the BO calls validate() on the VO, it passes itself in, so when the VO goes to perform the actual validations it's able to ask the BO for the data. Again, this keeps things encapsulated. I could change the implementation of either my BO or VO and nothing would break.

I do something similar to what Luis describes: I validate during population (to catch any datatype errors), and then I also validate after population (to check business rules). This allows me to report all validation failures back to the user.

Regarding the issue of a form field that is not persisted, I would take a different approach depending on what the actual requirements are. If it's really just about program flow then i'd argue that that isn't a validation at all, and would probably handle it in the controller. If it's about a property that doesn't need to be persisted in the database, like a "verify password" field, I usually create a property in my BO (via a getter and setter) for that, which allows me to validate it just like any other property. To me that is still an example of a business rule, and therefore it makes sense to have the rule defined in the business object.

In answer to your question about how the validator learns the rules, I use metadata for that. All of the business rules are defined once in the metadata, and are injected into the VO by the factory. The VO then knows how to perform all of the server-side validations, and can also generate all of the client-side validations, from the one set of metadata.

I'll be very interested to see where you go, as there are definitely many different ways of doing this.
# Posted By Bob Silverberg | 11/26/08 9:01 AM
BlogCFC was created by Raymond Camden. This blog is running version 5.9.1. Contact Blog Owner