voxpupuli / json-schema

Ruby JSON Schema Validator
MIT License
1.52k stars 241 forks source link

`oneOf` doesn't play well with `strict: true` #460

Open ngouy opened 2 years ago

ngouy commented 2 years ago

Let's have a schema with required property, and some other that are OR null, OR XOR required

I want this to validate like that :

{ "first_name": "Some", "last_name": "One" } OK { "first_name": "Some", "last_name": "One", "xor_property_1": null } OK { "first_name": "Some", "last_name": "One", "xor_property_1": null, xor_property_2: null } OK { "first_name": "Some", "last_name": "One", "xor_property_1": null, xor_property_2: "value" } OK { "first_name": "Some", "last_name": "One", "xor_property_1": "value", xor_property_2: "value" } KO

{
  "type": "object",
  "required": [ "first_name", "last_name" ],
  "properties": {
    "first_name": { "type": "string" },
    "last_name": { "type": "string" },
    "xor_property_1": { "type": ["null", "string"] },
    "xor_property_2": { "type": ["null", "string"] }
  },
  "oneOf": [
    {
      "required": ["xor_property_1"],
      "properties": {
        "xor_property_1": { "type": "string" },
        "xor_property_2": { "type": "null" }
      }
    },
    {
      "required": ["xor_property_2"],
      "properties": {
        "xor_property_1": { "type": "null" },
        "xor_property_2": { "type": "string" }
      }
    },
    {
      "properties": {
        "xor_property_1": { "type": "null" },
        "xor_property_2": { "type": "null" }
      }
    }
  ]
}

Per : https://json-schema.org/implementations.html#validator-web%20(online) When I validate the first example with any online validator, we are good (I'm adding the top level additionalProperties: false key to simulate the "strict")

image

With the gem :

image

The thing is that the oneOf code is forwarding the strict: true in the options here https://github.com/voxpupuli/json-schema/blob/master/lib/json-schema/attributes/oneof.rb#L21

But the schema, initiated line 18, that runs the validation is completely blind when it comes to the "root" allowed properties, so it considers that the oneOf schema is invalid, regarding its own schema vs the data

Also even if we are in strict mode, if we just remove the strict from oneOf it just works. Indeed if the parent is "strict" anyway, the validation error will append on the prior parent validation anyway

braindeaf commented 1 month ago

I think I am seeing the same thing. I want a nullable object, which if it does exist has two optional keys

schema = {
  "type"=>"object",
  "required" => ["a"],
  "properties" => {
    "a" => {
      "type" => "integer",
      "default" => 42
    },
    "b" => {
      "type" => "object",
      "properties" => {
        "x" => {
          "type" => "integer"
        }
      }
    }
  },
   'oneOf': [
     { required: ['a'] },
     { required: ['b'] },
  ]
}
JSON::Validator.validate!(schema, { 'a' => 1 })
JSON::Validator.validate!(schema, { 'b' => { 'x' => 1 } })
json-schema-3.0.0/lib/json-schema/attribute.rb:18:in `validation_error': The property '#/' did not contain a required property of 'a' (JSON::Schema::ValidationError)

But I don't wish to have a required value of 'a' :S