How to validate an array of different objects using dry-schema gem

1.4k Views Asked by At

Given I have such JSON object having an array of various objects like:

{
  "array": [
    {
      "type": "type_1",
      "value": 5
    },
    {
      "type": "type_2",
      "kind": "person"
    }
  ]
}

According to JSON schema validation, I can validate this schema using this JSOM schema definition:

{
  "type": "object",
  "properties": {
    "array": {
      "type": "array",
      "items": {
        "oneOf": [
          {
            "type": "object",
            "properties": {
              "type": {
                "type": "string",
                "enum": [
                  "type_1"
                ]
              },
              "value": {
                "type": "integer",
                "enum": [
                  5
                ]
              }
            }
          },
          {
            "type": "object",
            "properties": {
              "type": {
                "type": "string",
                "enum": [
                  "type_2"
                ]
              },
              "kind": {
                "type": "string",
                "enum": [
                  "person"
                ]
              }
            }
          }
        ]
      }
    }
  }
}

How can I validate the input JSON using the dry-schema gem? Do you have any ideas?

1

There are 1 best solutions below

0
On

To tackle your problem, try this code:

class TestContract < Dry::Validation::Contract
  FirstHashSchema = Dry::Schema.Params do
    required(:type).filled(:string)
    required(:value).filled(:integer)
  end

  SecondHashSchema = Dry::Schema.Params do
    required(:type).filled(:string)
    required(:kind).filled(:string)
  end

  params do
    required(:array).array do
      # FirstHashSchema.or(SecondHashSchema) also works
      schema FirstHashSchema | SecondHashSchema
    end
  end
end

valid_input = {
  array: [
    {
      type: 'type_1',
      value: 5
    },
    {
      type: 'type_2',
      kind: 'person'
    }
  ]
}

TestContract.new.call(valid_input) #=> Dry::Validation::Result{:array=>[...] errors={}}


invalid_input = {
  array: [
    {
      type: 'type_1',
      bad_key: 5
    },
    {
      type: 'type_2',
      kind: 'person'
    }
  ]
}

TestContract.new.call(invalid_input) #=> Dry::Validation::Result{:array=>[...] errors={:array=>{0=>{:or=>[...]}}}

The key thing here is the method #schema. Documentation