Ignore nested key validation

Hello and thank you for all the hard work on the Dry suite of gems,

I have one usage issue I’d like to try and clarify. I have a schema similar to

class MyContract
  params do
    optional(:pickup_address).filled(:hash, AddressContract.schema)
  end
end

class AddressContract
  params do
    optional(:contact).filled(:hash, ContactContract.schema)
  end
end

class ContactContract
  params do
    optional(:name).filled(:string)
  end
end

and am validating request keys using config.validate_keys = true

The “problem” I’m having is when a nested/ hash type parameter is sent that isn’t specified in the schema then the entire flattened object will be returned as an error.

An example would be

MyContract.call({ pickupaddress: { contact: { name: 'John' } } })

=> #<Dry::Validation::Result{} errors={:pickupaddress=>{:contact=>{:name=>["is not allowed"]}}}>

In this instance, I would expect the error to only reference the top-level key :pickupaddress, as MyContract should only be validating the keys it has defined, and not nested keys of things that aren’t defined (in my eyes). If something like { pickup_address: { contact: { contact_name: 'John' } } were sent then I would expect the nested errors to include the undefined keys from any of the nested schemas.

In this case, I’m hoping to achieve something like errors={:pickupaddress=>["is not allowed"] with no mention of the nested keys/ errors. I’ve tried multiple attempts using custom rules, dry-schema preprocessor steps (before(:rule_applier), and removing the key validation from the config, but the result is usually that the schema has already thrown out any keys that weren’t defined and I am unable to access them within the rule.

Any suggestions I might have missed to ignore the keys of these undefined objects?

Thank you

1 Like

the closest I have come is adding an error for the top-level key, but this adds it in addition to the nested error and I’ve not been able to find a way to remove errors after they’ve been added to the result.

Any changes to result.errors.to_h don’t seem to apply to the actual error message set, any tips on that would be greatly appreciated.

before(:value_coercer) do |result|
  result.add_error([:failure, ["pickupaddress", [:key, [:pickupaddress, [:predicate, [:nil?, [[:input, :pickupaddress]]]]]]]])
end

#>  #<Dry::Validation::Result{} errors={:pickupaddress=>[["is not allowed"], {:city=>["is not allowed"]}]}>