Apply nested schema to all values of a hash

Hello there,

I’d like to validate this structure:

paths:
  random_key_one:
    get:
      description: 'Hello'
  random_key_2:
    put:
      description: 'World'

I want to check, for each value of the paths hash (so, for any key of the hash) that it has a get or a put nested object with a description attribute.

I didn’t find any way to apply a nested schema in this situation. Does somebody have a hint for me?

Thanks a lot, and sorry for my trivial question.
Sébastien

This is unsupported, you can track this feature request in dry-schema https://github.com/dry-rb/dry-schema/issues/37
As a workaround, you can write a rule for :paths and iterate over keys there.

Thx for your quick answer @flash-gordon, and for the hint. I cannot find any example for this kind of situation, if you have a few minutes, could you please help me with that part (iterating over keys)?

I can guess that it starts with something like this, but I’m still confused on the validation part:

rule(:paths) do
  value.each do |(k, value)|
    # How to check that `value` matches a specific schema, AND to set the errors at the correct path?
    # Something like...
    key([:paths, k]).failure('invalid') if #what ?
    # But how to merge error messages of the nested schema test?
  end
end   

Thanks a lot.

There’s no standard solution for merging errors automatically, you’ll need to do it manually in the way that works for you. For example, I have code like this in one place

rule(:some_collection).each do
  case validate_element.(value) # some other contract injected above
  in Success then nil
  in Failure(errors)
    errors.each do |path, messages|
      key([:some_collection, *path]).failure(message)
    end
  end
end

:wave: , thanks for your answer, it helped a lot :slight_smile:

I finally got this working:

rule(:paths) do
  value.each do |(key, value)|
    PathSchema.call(value).errors.each do |error|
      key([:paths, *error.path]).failure(error.text)
    end
  end
end
1 Like