Skip to content

Instantly share code, notes, and snippets.

@gregopet
Last active June 19, 2023 19:19
Show Gist options
  • Save gregopet/276aa78c00e67544bf6e374848728c25 to your computer and use it in GitHub Desktop.
Save gregopet/276aa78c00e67544bf6e374848728c25 to your computer and use it in GitHub Desktop.
Validation library requirements

What I expect from a validation library

I’m documenting for myself what I would look for in a validation library. The code I currently need it for is in Kotlin so I have the entire JVM ecosystem to choose from.

JSR 303 and JSR 349

Certainly well battle tested but I dislike the annotations approach; while nice for simple validations it can get hairy when testing real scenarios: inter-dependent objects, database access and external services all need to be wired in somehow and I really don’t want to get to the point where I am solving problems of my library rather than my own.

…​ too many battle scars …​

Also, working with jOOQ’s Record I don’t really have domain objects to easily annotate.

And of course the library is extremely Javaesque - the first step of a tutorial begins with creating your very own ValidatorFactory: Validation.buildDefaultValidatorFactory() - I’m in the mood for something lighter.

Functional approaches

There are a few functional approaches for the Java ecosystem out there that either abuse Java’s Stream or start gushing about monads in paragraph 2 of the docs and neither of those are very appealing to me.

Kotlin Validation

Looks interesting, but is light on documentation which is really not good. Also poor commit discipline.

So let’s start gathering requirements

Readable and flexible tests

All validation libraries seem to get readability, at least when it comes to the simple cases. The JSRs allow you to annotate things like @NotNull @Size(min=1, max=16) and the functional examples use lambdas. Flexibility is not a given anymore - annotations have a hard time seeing related objects unless they are in the same object hierarchy.

In Kotlin, functions seem like the perfect candidates; we can reuse the general ones in and easily write more specific tests, inline if more convenient.

Easily selecting which properties should be validated, if we don’t need them all (while keeping code DRY), seems trickier but doable.

But what should the functions return? A Validation object? Exceptions? Should they be a part of a larger Validation objects and modify its state or should they be purer and simply return some sort of ValidationError objects when something goes wrong?

Feedback

We need to provide feedback to the user - what went wrong?

We need to list the errors, translated, and know which errors belongs to which specific properties of the object under validation, and which are general errors (and we also need a convenient way to detect and identify these errors programatically).

It would be good to be able to see the original object, perhaps as it currently exists in the database. It would be good to be able to get the new value of a property as it will get stored in the database when the user solves the validation issues.

Various severity levels of the errors would also be good - sometimes we would just like to warn the user, e.g. when a password is too simple.

Making it easy to build UI renderers for the errors and plug them into whatever I am using would obviously be nice.

Configurability

Grouping validations would be great so the same group of tests can be applied to multiple entities (preferrably with gracefull fallbacks when a validation step cannot be used) - but not at the expense of type safety - union types would be very handy here.

Validation read in from somewhere (config files, databases..) would be a nice feature as well, either full-blown or simply to turn some validations on/off.

Introspection

Being able to know which validations will be applied to a given object property could sometimes be useful.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment