dry-validation – The one gem to validate them all! | Hanami Mastery

dry-validation - The one gem to validate them all! | Hanami Mastery

In the last episode, I’ve talked to you about the dry-schema features allowing you to easily validate data structures and attributes types in your ruby applications.

However powerful, it’s not dry-schema that is the mostly used DRY library. It’s another gem, built on top of that engine which extends it’s functionality.

It’s dry-validation and this is what I’ll talk today about.

What is dry-validation?

dry-validation is a data validation library for all kinds of ruby applications, that provides complete set of features you’d need to validate anything.

  1. It uses dry-schema for data structure and type validation, which is great on its own!
  2. Extends the functionality to add business validations.
  3. Allows injecting external dependencies
  4. Allows writing custom macros.
  5. It plays extremely well with dependency injection

I have recorded two episodes about how to do dependency injection in ruby like a PRO using DRY-libraries, so feel free to check them out!

When to use dry-validation?

If you have projects, where there is not too much of the business logic to be validated, chances are that dry-schema standalone would be enough for you.

However, when you want to add more advanced validation, like

  • email uniqueness,
  • validating attributes based on others provided,
  • connect to external apis ,
  • display powerful YAML-based error messages

then dry-validation is the way to go.

In Hanami, you have access to both gems, as dry-schema is a subset of dry-validation, and in the actions, it’s usually ok to just validate the data structures.

Let me show you a few nice features specific for dry-validation.

If you want to use dry-validation in your project, this video shows just a subset of features – the whole functionality provided by dry-schema is omitted here, as I’ve covered this gem in two of my previous episodes. Check them out to have a complete overview of validation power you get for free in Hanami applications.

So let’s go over a few things that are cool in dry-validation.


As an addition to built in structure and type check, dry-validation allows you to define custom validation rules.

Here I have a contract, that validates the start and the end date of my reservation.

class ReservationContract < Dry::Validation::Contract
  params do

  rule(:from, :to) do
    key.failure('must be after start date') if values[:to] <= values[:from]

The params section is a simple validation that is provided by dry-schema. It checks the input and applies the basic transformations if applicable, to ensure I’ll work with the data of expected types.

If this basic validation fails, program stops there, and does not even reach the advanced validation rules, which is an extremely nice boost to the performance!

Only when the basic validation passed, we reach the advanced validation rule , which compares two different attributes and returns the error response in case of expectations not being met.

Now I can use it by creating the contract and calling it with some attributes and checking the error responses.

contract = EventContract.new
result = contract.call(from: Date.today, to: Date.today - 1)



Custom macros

In case you have a very common validation scenario, like email validation, that should be the same across your whole application, you may save some code duplication by extracting this validation rule, to a macro!

Dry::Validation.register_macro(:email_format) do
  unless /\A[\w+\-.]+@[a-z\d\-]+(\.[a-z\d\-]+)*\.[a-z]+\z/i.match?(value)
    key.failure('not a valid email format')
class HanamiMasterySubscriptionContract < ApplicationContract
  params do


This makes the syntax extremely easy to use, while keeping the gem very simple concept-wise.

However, it’s not the end.

Injecting external dependencies

As in addition you may inject the external dependencies to the contract. For example, you may pass here in the repository object, or activerecord model to check if given user has already subscribed to your newsletter!

class HanamiMasterySubscriptionContract < Dry::Validation::Contract
  option :repo

  params do
  rule(:email) do
    unless repo.exists?(values[:email])
      key.failure("I appreciate you want to subscribe twice but we don't want to spam you!") 

Now I can pass the repo to the contract using dependency injection, and validate freely the uniqueness of my email.

class Repo
  def exists?(email)

contract = HanamiMasterySubscriptionContract.new(repo: Repo.new)
result = contract.call(email: 'awesomesubscriber@hanamimastery.com')


This works perfectly in Hanami applications, where you have dependency injection integrated as the main way to manage dependencies, however, I have used it in Rails apps in the past too and it worked great withactiverecord objects!


The next feature I wanted to show you, is the fact that dry-validation is extendable. dry-validation comes with two extensions built-in which you can enable if you want, but you can also write your own whenever you need them.

Here is an example of monads extension, which makes your contracts compatible with dry-monads.

I strongly recommend checking that one too! I’ve covered it in HME007 which is the most popular episode I’ve recorded so far!

To use it I need to enable monads extension somewhere in your app code

require 'dry/validation'


And now, I can treat my contracts as monads, making use of all the operations dry-monads provides

class MyContract < Dry::Validation::Contract
  params do

my_contract = MyContract.new

my_contract.(name: "")
  .fmap { |r| puts "passed: #{r.to_h.inspect}" }
  .or   { |r| puts "failed: #{r.errors.to_h.inspect}" }

If you want to know more, I recommend checking out the DRY in Five Youtube series by Luca Guidi, which is a nice intro to this gem. And, if you want to get the always up-to-date information, make sure you follow the DRY-RB on twitter and visit the gem’s documentation!


dry-validation is an amazing library. It’s the most popular DRY gem released so far, and there is a reason for this.

The funny thing is that people often use it in Rails applications, skipping strong_parameters and active_model validations completely, as this one is more safe and faster.

Unfortunately, this is all I’ve for today! I hope you enjoyed this episode and stay in touch to get updates about my upcoming content!


I want to especially thank my recent sponsors,

By helping me with monthly github sponsorship to create this content, together we really start making a difference in the Open-Source world! Thank you all for your support!

And remember, if you want to support my work even without money involved, the best you can do is to like, share and comment on my episodes and discussions threads. Help me add value to the Open-Source community!

Also big thanks to Thibault Luycx for a great cover image!

Do you know great Ruby gems?

Leave a comment with #suggestion, I’ll gladly cover them in the future episodes!

Source link

Leave a reply

Please enter your comment!
Please enter your name here