parris/iz — pull request #8 by eldonferrandepol (2013-05-17 10:11:43+00:00)
Title: Full separation of mandation and value validity

This is a significant change that fundamentally changes the way that the module works but introduces a paradigm that we have found very useful. Would be interested in discussing further but would fully understand if you feel that it alters iz too much. Essentially it completely separates out "presence" of a value from whether that value is "valid".

We think that this provides an interesting usp compared to other validation frameworks and makes it perfect for the kind of boundary validation that we are doing. However, it does make some of the validators handle null and undefined in a counter intuitive fashion. Basically iz.someValidator(null) and iz.someValidator(undefined) will return true!!! The paradigm is shifted from "is this an email" to "assuming that I have a value at all, is it an email".

As I said above we are using iz primarily for boundary validation against incoming payloads rather than against single values. As such, we care about two things for each field on a given payload. Is it a mandatory field (yes/no) and does it require some validation (yes/no). By way of explanation here are some examples of why we have found this change so useful:

Example payload:
{
name: mandatory,
email: mandatory/a valid email,
startDate: non-mandatory/'a valid date,
}

Previously to these changes the handling of mandatory was not particularly explicit and, in particular, the client code HAD to be responsible for handling null & undefined in some cases (startDate below). Validation would have looked this:

iz(payload.name).not().blank()
iz(payload.email).email()
if(payload.startDate !== null && payload.startDate !== undefined)
{
iz(payload.startDate).date()
}

One thing that we wanted to address here is that the mandatory nature of name and email is not explicit. More importantly the startDate validation is not very nice at all. Because iz currently defaults to false when calling iz(payload.startDate).date() it is impossible to express the idea that startDate is not required but must be a date when it is provided. This means that a very common validation requirement (whether fields are required or not) is a little cumbersome.

By switching the default behaviour of validators to be "only validate a value if one is provided" things start to look explicit.

iz(payload.name).present() //must have a name of some sort
iz(payload.email).present().email() //must have an email and it must be a valid one
iz(payload.startDate).date() //date is not required but must be valid when provided.

Sorry for the length of this request but I felt it important to be clear how fundamental the change is (major version increment I think) but also why we felt it worth putting in a pull request for it despite that.