Hey all!
I was using dry-validation and dry-types and ran into some odd behavior that feels somewhat unexpected. The situation came from using a Constructor
type for a class that was, itself, using a dry type inside the initalizer.
Basically, on calling the contract a CoercionError bubbles all the way up (instead of being nested in the errors as I’d expect). I’m guessing this has to do with how Constructor types are “constrained” in dry types, but my expectation is that filled
on a Contract would first reject any nil
input.
Here’s a reproduction script to showcase what I mean.
module Types
include Dry.Types()
end
# Later
class Thing
CleanString = Types::Strict::String.constructor(&:strip).constructor(&:downcase)
def initialize(input_string)
@thing = CleanString[input_string]
end
end
module Types
Thing = self.Constructor(::Thing)
end
class SomeContract < Dry::Validation::Contract
json do
required(:thing).filled(Types::Thing)
end
end
SomeContract.new.call(thing: nil)
# => Dry::Types::CoercionError: undefined method 'strip' for nil:NilClass
# With "Thing" using .try - bad result :(
class Thing
CleanString = Types::Strict::String.constructor(&:strip).constructor(&:downcase)
def initialize(input_string)
@thing = CleanString.try(input_string)
end
end
# Input looks "valid"
SomeContract.new.call(thing: nil)
#<Dry::Validation::Result{:thing=>#<Thing:0x00007f93b6ae2698 @thing=#<Dry::Types::Result::Failure input=nil error=#<Dry::Types::CoercionError: undefined method `strip' for nil:NilClass>>>} errors={}>
# With "Thing" without using Dry::Types at all
class Thing
def initialize(input_string)
@thing = input_string.strip.downcase
end
end
SomeContract.new.call(thing: nil)
# => #<Dry::Validation::Result{:thing=>nil} errors={:thing=>["must be Thing"]}>
– edit –
meant to also say that I did some prior reading here: Contract ignores ConstraintError thrown by Dry::Types[Constructor]
Which is close, but not exactly what I meant. I don’t expect some custom constraint message, at most I just expected that there wasn’t an outright error bubbled up.