Validating ordered array of multiple types

You could do this:

require 'dry/validation'

class Contract < Dry::Validation::Contract
  params do
    required(:items).value(:array, size?: 2).each(:hash) do
      required(:id).value(:string)
      required(:thing).value(:integer)
    end
  end

  rule(:items) do
    key([:items, 0, :id]).failure('id must be asdf') unless value[0][:id].eql?('asdf')
    key([:items, 1, :id]).failure('id must be jkl') unless value[1][:id].eql?('jkl')
  end
end

data = {
  items: [
    {
      id: 'asdf',
      thing: '1234'
    },
    {
      id: 'jkl',
      thing: '2345'
    }
  ]
}

contract = Contract.new

puts contract.(data).errors.to_h.inspect
# {}

data = {
  items: [
    {
      id: 'foo',
      thing: '1234'
    },
    {
      id: 'bar',
      thing: '2345'
    }
  ]
}

contract = Contract.new

puts contract.(data).errors.to_h.inspect
# {:items=>{0=>{:id=>["id must be asdf"]}, 1=>{:id=>["id must be jkl"]}}}