We had a couple of big dry-v releases this month - 0.8.0 quickly followed by 0.9.0. Both versions brought a lot of improvements, bug fixes and new features. The codebase is becoming easier to work with, simpler and better structured, which gives us much confidence that things we’d like to do for 1.0.0 are not that far away. So, here’s what we’re planning.
Simpler & faster message compilation
dry-validation is built on top of dry-logic gem, which provides the foundational
Predicate APIs (which is also used by dry-types’
Constrained API), this library uses an AST that describes its rule and result structures. Designing the AST format has been a long process, and we finally know how to make it simpler and easier to process for dry-validation. We’re going to come up with a final structure soon and update both dry-logic and dry-validation to use the updated format. This is a huge improvement, as most of the bugs we’ve had were caused by difficulties in result-ast processing. All of the known issues have been fixed, but there are a couple of implementation details that could be greatly simplified, which will also result in significant performance improvements. That’s why this is one of the priorities for 1.0.0.
Hints as a first class feature
In 0.9.0 a new abstraction has been introduced called
MessageSet which provides access to
Message objects, which are divided into
Hint types. This is a great start for finalizing our unique Hints feature, that will be improved and promoted to a first-class API.
There are two major improvements that we plan to do for 1.0.0:
MessageSetwill be able to reject messages with lower priority than other messages. This means that some failure messages might be rejected because we have more meaningful failures or hints available. Simple example: when
filled? & format?(/some-regex/)fails because the value was empty, we’ll be able to reject the “must be filled” failure and only return “must have a format /some-regex/” hint because it will have bigger priority than
filled?predicate. This will allow us to reduce the amount of messages that are being returned to the client.
MessageSetwill provide APIs for accessing messages and hints separately, in case you’d like to handle them in a different way in your UI
We’d like to improve the UX of dry-validation by configuring which predicates should be applied too based on configurable requirements. A common example is doing
value(format: /some-regex/) and then seeing it crash because a nil was passed in and we forgot to add
str? check. Because of that we’re going to make macros smarter so they will know that in some cases an additional predicate must be applied.
Configurable Success/Failure modes
Right now dry-logic produces result objects for both success and failure rules. This has a pretty terrible impact on the performance, because in most of the cases you don’t really care about success results, you only care about failures. Because of that we’re going to make it configurable and more useful too:
- Success results won’t be returned by default, which will speed up validation a lot
- You’ll be able to turn on success results and
Validation::ResultAPI will provide a way for accessing these results, this should be useful in things like data audits where you need to generate a detailed report showing which rules passed and which failed
Schemas as Rules
Schema already implements some of the
Rule interface, but in 1.0.0 we want to make it work just like rules from dry-logic. This will allow you to define multiple schemas and “chain them” logically using rule logic operators ie
schema1.and(schema2.or(schema3)) - this will be useful in really complex cases where multiple validation steps must be taken with different paths, depending on the input.
Restricted Hash Input
Right now dry-validation rejects unspecified keys, so there’s no way to tell if there were any unexpected keys. We’d like to have a rule type that can be applied against a hash and tell you which keys were not expected. See this issue for more information.
Final API for type-specs
In 0.8.0 we introduced a new way of specifying expected types for individual values ie
required(:name, [:nil, :str]).filled(:str?). This way we completely separated type-specs that are used for coercion from the validation rules. This is still experimental, and we’re exploring how exactly we’d like to use dry-validation schemas for handling coercion and validation. One idea that we have is to use separate schemas exclusively for basic coercion and validation, and other schemas for more domain-specific validations. This still needs some investigation and experimenting.
And probably more…
These are the major goals that we’d like to accomplish prior 1.0.0. There will be many smaller improvements, like a nicer way of including rules from multiple schemas, more polished Messages API so that it’s easy to provide your own backend, maybe a couple of new macros for boilerplate reduction etc.
If you think something is missing here, please let us know!