loading...
Cover image for Fight Validations Spaghetti with Vest.

Fight Validations Spaghetti with Vest.

ealush profile image Evyatar Alush ・4 min read

tl;dr - Vest is a new validations framework I have been working on. I believe it makes validations a little bit cleaner and easier to maintain.


One of the problems that I see repeating the most in many projects is related to form validations - regardless of whether the project uses one framework or another (or not at all).

I’m not saying that validating forms is difficult or complicated, but that it’s really easy to write them in ways that will lead us into trouble down the road.

I am trying to solve it with Vest (Validation tEST), an open-source project that I have been working on, and has proved its effectiveness in my previous workplace over and over again.

What's wrong with form validations?

Before I elaborate about Vest itself, I’ll try to touch on the main problems I see in the world of validations.

After a while, validation logic tends to grow and be filled with spaghetti code:
In the beginning, when we write a new feature with forms, we make sure everything is clean and tidy. Many times what happens is that a new product request arrives and adds or changes features in that form that changes the technical design of the feature itself. What we usually do to finish on time is just bash it in until it works. After a while, this becomes an unmaintainable monster.

Nothing is reusable:
The way people usually write JS validations is pretty much like this - we have an input and some change handler that takes care of it. We usually write it along with the form itself, because that’s where it makes the most sense. But what about validation logic that repeats in different places across the site - such as password, or email?
Since we write our validations inside our features itself, we can’t easily use it in other places, and what we do is make an overly generic function that takes care of too many stuff, or copy/paste our logic and make it a maintenance nightmare.

It is very hard to refactor features:
When we write our validations they will usually be tied to the framework we’re using, this leads to the fact that if we ever want to make a change, such as update or replace the framework we’re using, or just refactor the feature, we can’t do that without re-writing our validations from scratch.
These are not the only ones, and of course, not every one of them is relevant in every scenario, but I am sure there is a general agreement that working with form validations can very easily lead to a big mess - even if not always.

Welcome Vest

Vest is an open-source framework I have been on for the past couple of years. I implemented its early versions in my previous workplace, and it helped a lot with bloat and maintainability.

Vest introduces nothing new, really, but it tries to re-think form validations with structures you are already familiar with. With Vest, we structure our validations with unit-test-like syntax that's completely separate from our feature code.

Vest Example

The idea is to not worry about which framework we use, or what is our feature structure. We look at our validations as a series of tests that our data needs to go through to be considered valid.

The syntax is simple, intentionally similar to what you would expect to see in testing frameworks such as Jest and Mocha, only that instead of describe/it/expect, you use validate/test/enforce.

  • validate: Is your suite wrapper. It initiates a Vest instance.
  • test: A single validation unit, it takes a field name (you can have more than one test for a single field), the message to display to the user in case of an error, and the test body.
  • enforce: An assertion function, very much like expect, only focused on data validation.

Among Vest's features

Vest provides you with a large set of tools and features to describe and manage your validations, you should look at the documentation for a full list - but here are some of the more useful ones.

  • Warn only tests:
    You don't always want failed validations to fail the whole suite, for example when validating password strength. You may want to just show a warning to the user instead, and allow them to register regardless. This can be done with the vest.warn() hook.

  • Excluding or including tests:
    When validating user inputs, we usually want to only perform our validations on fields that the user interacted with. Vest includes the vest.skip() and the vest.only() hooks that allow you to determine which fields to tests.

  • Async tests support:
    When validating your features, you might need to query the server for some data that do not exist in the browser, for example - if a username already exists. Vest supports Promise(or async/await) tests, so you can describe it is a part of your suite.


If you find any of these interesting, I would really appreciate it if you gave Vest a try. It helped me and others when working on features, you might find it helpful as well.

GitHub
npm
Documentation

Thanks!

Posted on by:

Discussion

pic
Editor guide
 

I've been thinking a lot about how to deal with validation in the simplest most consistent form possible and will take a look at vest!

Wanted to ask; what are your thoughts on JSON schema? Pro's/con's on using JSON schemas with a validation library to specify validation?

 

JSON schemas are great. I think that schema validation tools give you the ability to validate stuff that are usually pretty hard, or just redundant.

The thing that's a bit harder to do with schema validations is integrating them as a part of your feature logic, for example validating a specific field upon interaction. Another thing that can be annoying is dealing with warn only validations (does a medium strength password match, or not match the schema, then? How do you know to present a warning there?).

Schemas are mostly useful when you want to validate your whole form at once (upon submit, for example). Validating as the user types is a bit of a hassle.

It is possible, though, to use both vest and the schema validation library of your choice. You are not coupled to enforce as your assertion library. You can base your validations on anything that either throws an error, or explicitly returns false for an invalid test - so whatever you're using now, you can keep using it within vest.

 

man thanks a lot that is really helpful perspective, esp. re useful for validating a whole form vs specific fields!

"You can base your validations on anything that either throws an error, or explicitly returns false" sounds really flexible :)

Thanks :)
The intention is not flexibility (took me a while to realize flexibility isn't always a good thing), but to allow easy migration of existing validation logic. Validations are usually boolean based, so this helps with that.