Validating complex structures can quickly become a challenge. Akkurate has been designed from scratch for this task and provides you everything you need for any complexity levels.
Despite using a declarative approach for validation, Akkurate doesn't enforce you to use it and even encourages you to switch to imperative code when needed.
When validating arrays, maps or iterables, you can use a normal loop to iterate over each item:
Since iterating over a collection to validate its items is a common task, Akkurate also provides the
You can use conditions to apply constraints only when needed. Let's say our
Library has a maximum capacity:
The maximum capacity is infinite when it's equal to 0, so we want to constrain the size of the book collection only if the maximum capacity is at least 1. To achieve this, we can unwrap the value, add a condition, and create a constraint only if its positive.
Sometimes, you need to apply a constraint depending on the result of a previous one, like Twitter has to do in its settings when a user wants to update its username.
When Twitter launched, you could pick a one-character username. However, this is no longer possible; you're now forced to use at least five characters.
Now imagine being Twitter's product owner for today's settings page. Someone tries to change its username to “a”. This is less than five characters, and it already exists. So, what errors do you want to display?
Two errors? One about character count, and another one about an already taken username?
Or only one error about character count?
The answer is the second one:
Since new users can't register with handles shorter than 5 characters anyway, Twitter chose to skip the database check when the username is too short. Avoiding an unnecessary database query and restraining error spamming for the user.
This is a typical use case for conditional constraints. When a constraint is applied, you can read its
satisfied property to check if the constraint is satisfied or not.
It is common to validate the same properties in different places. To avoid applying the same constraints multiple times, you can use composition to reuse a validator inside another one.
Here we have a
Person class used by two different properties:
reviewers. To avoid code repetition, we create a validator for the
Person class and then call it from
You might sometimes need to check if two values are equal:
.unwrap() everywhere can quickly become cumbersome. This is why
hashCode as pass-through methods to the underlying value. Which means you can remove the calls to
unwrap to check for equality: