Introducing Sandra.SimpleValidation - Validation reinvented... again

posted on 25 Jan 2013

Yup, I decided to reinvent the wheel, don't hate on me :)

So I grew a little fustrated, theres quite a few serverside validation libraries around, but I feel they do too much, are hard to test, yada yada yada...

So I came up with Sandra.SimpleValidation

The idea is that it's dead simple, it requires 0 up front configuration, it doesn't allow you to inject stuff into the validators, validators are newed up once and only once, there's no client-side validation.

I don't believe validation should allow you to do things like inject a repository and query the database, those begin to become Business Rules and should be handled seperately. All it does is validate a model you give it.

So what do you need to do?

PM> Install-Package Sandra.SimpleValidator

First up, install the package. It requires 4.0 or above, it could probably work on 3.5 but who uses that anymore?

Once installed, you can create a validator

public class UserValidator : ValidateThis<User>
{
    public UserValidator()
    {
        For(x => x.Username)
            .Ensure(new Required());

        For(x => x.Email)
            .Ensure(new Required())
            .Ensure(new Email());

        For(x => x.Locale)
            .Ensure(new Required());
    }
}

If you don't like the default messages you can change those by chaining the rule like so

public class UserValidator : ValidateThis<User>
{
    public UserValidator()
    {
        For(x => x.Username)
            .Ensure(new Required().WithMessage("Username is required");

        ...
    }
}

Now you can inject (or create an instance of) the ValidationService.

Using Nancy with the default TinyIoC container, you can just include this in the module constructor. If you're using MVC you may need to register it depending on the container you're using. In any case it can be a singleton since it only needs to be created once.

public class HomeModule : NancyModule
{
    public HomeModule(ValidationService validate)
    {
        Get["/"] = _ =>
        {
            var user = this.Bind<User>();
            var validationResult = validate.This(user);

            if (validationResult.IsInvalid)
            {
                //Handle errors with
                //validationResult.Messages

                return "Validation has fails :(";
            }

            return "Validation was successful :)";
        };
    }
}

Once you've injected the service, you simply call This(...) passing in the object you want to validate. With the result you can then call IsValid or IsInvalid and handle the errors.

What's nice about the validator class is that because it's so simple, it's simple to test. Given the example above, we can write a unit test like so.

[Fact]
public void Given_Valid_Model_Should_Return_IsValid_As_True()
{
    var validator = new UserValidator();
    var model = new User
    {
        Username = "HelloWorld",
        Email = "test@banana.com",
        Locale = "en-AU"
    };

    var result = validator.Validate(model);

    Assert.True(result.IsValid);
}

That's all there is to it. Currently as of writing this it only supports Required, MinimumLength, MaximumLength, Between, and Email rules. Since that's all I require for my current project. If you want to create your own simply implement IRule and new them up in the Ensure method of the validators.

In the future I hope to get Nancy intergration so the validation can be invoked on this.Bind<T>(), but for now you can find the github repo, and nuget

https://github.com/phillip-haydon/Sandra.SimpleValidator https://www.nuget.org/packages/Sandra.SimpleValidator

comments powered by Disqus