Simon Mathai
Simon Mathai

Reputation: 11

Best Match for Validation error with oneof or anyof

I am trying to get proper validation error from oneof or anyof pattern. I have json schema with two or more oneof/anyof condition as mentioned below:

json_schema =  {
    "type": "object",
    "properties": {
        "comment": {
            "description": "Server Pool Policy Qualification Comments",
            "type": "string",
            "default": ""
        },
        "name": {
            "description": "Server Pool Policy Qualification Name",
            "type": "string",
            "default": "",
            "pattern": "^[\\-\\.:_a-zA-Z0-9]{1,16}$"
        },       
        "qualifications": {
            "description": "Qualifications of Server Pool Policy Qualification",
            "type": "array",
            "items": {
                "description": "Qualification of Server Pool Policy Qualification",
                "type": "object",            
                "oneOf": [                               
                    {
                    "properties": {
                        "type": {
                            "description": "Qualification Type",
                            "type": "string",
                            "enum": [
                                "adapter"
                            ]
                        },
                        "adapter_qualification":{
                            "description": "Adapter Qualifications - Adapter Type",
                            "type": "array",
                            "properties": {
                                "adapter_type": {
                                "description": "Adapter Qualifications - Adapter Type",
                                "type": "string",                              
                                "enum": [
                                    "virtualized-scsi-if"
                                ]
                                },
                                "adapter_pid": {
                                "description": "Adapter Qualifications - Adapter PID (RegEx)",
                                "type": "string",
                                "default": "",
                                "pattern": "[ !#$%\\(\\)\\*\\+,\\-\\./:;\\?@\\[\\\\\\]\\^_\\{\\|\\}~a-zA-Z0-9]{0,256}"
                                },
                                "adapter_maximum_capacity": {
                                "description": "Adapter Qualifications - Maximum Capacity",
                                "type": "string",
                                "default": "unspecified",
                                "pattern": "^unspecified$|^[0-9]$|^[0-9][0-9]$|^[0-9][0-9][0-9]$|^[0-9][0-9][0-9][0-9]$|^[0-5][0-9][0-9][0-9][0-9]$|^6[0-4][0-9][0-9][0-9]$|^65[0-4][0-9][0-9]$|^655[0-2][0-9]$|^6553[0-5]$"
                                }
                            },                     
                            "additionalProperties": False,
                            "required": [
                                "type",
                                "adapter_type"
                            ]                        
                        }                     
                        }
                    },                 
                    {
                        "properties": {
                            "type": {
                                "description": "Qualification Type",
                                "type": "string",
                                "enum": [
                                    "server_pid"
                                ]
                            },
                            "server_pid": {
                                "description": "Server PID Qualifications - Server PID",
                                "type": "string",
                                "default": "",
                                "pattern": "^123$"
                            }
                        },
                        "additionalProperties": False,
                        "required": [
                            "type",
                            "server_pid"
                        ]
                    }
                ]
            }
        }
    },
    "additionalProperties": False,
    "required": [
    "name"
    ]
}

I have data which has additional element first_rack_id but best matches 2nd element from oneof.

data = {
    "descr": "description",
    "name": "domainGroup",
    "qualifications": [
    {
        "server_pid": "B200M5",
        "type": "server_pid",
        "first_rack_id": "10"
    }                             
    ]
}
validator = Draft7Validator(json_schema)
best = best_match(validator.iter_errors(data))

My expectation is that the error message thrown by validation will find 2nd element from oneof and throw error saying additional property is not allowed. but i get match for 1st element as mentioned below:

'server_pid' is not one of ['adapter']
Failed validating 'enum' in schema[0]['properties']['type']:
{'description': 'Qualification Type',
 'enum': ['adapter'],
 'type': 'string'}

On instance['type']:
'server_pid'

how do i specify validator to best match with property "type" which will match with enum "server_pid" instead of enum "adapter"

Upvotes: 1

Views: 3190

Answers (2)

Heath Kang
Heath Kang

Reputation: 71

Since best_match need a sort key to help match errors and the default key is to use most depth errors key, see:

  1. best_match
  2. relevance

So maybe you can use a less depth key to match the errors.(below function is just a draft test, you can use it as reference)

def match_less_path(error):
    return len(error.path)

best = best_match(validator.iter_errors(data), match_less_path)

And I test the output like this:

Additional properties are not allowed ('first_rack_id' was unexpected)

Failed validating 'additionalProperties' in schema[1]:
    {'additionalProperties': False,
     'properties': {'server_pid': {'default': '',
                                   'description': 'Server PID '
                                                  'Qualifications - Server '
                                                  'PID',
                                   'pattern': '^123$',
                                   'type': 'string'},
                    'type': {'description': 'Qualification Type',
                             'enum': ['server_pid'],
                             'type': 'string'}},
     'required': ['type', 'server_pid']}

On instance:
    {'first_rack_id': '10', 'server_pid': 'B200M5', 'type': 'server_pid'}

Upvotes: 0

Jason Desrosiers
Jason Desrosiers

Reputation: 24439

You can specify which schema to validate against with the if/then keywords. It's a bit verbose and can be error prone, but it's the best way to express this sort of thing. Although popular, oneOf is almost never the right choice.

  "allOf": [
    {
      "if": {
        "type": "object",
        "properties": {
          "type": { "const": "adapter" }
        },
        "required": ["type"]
      },
      "then": { "$ref": "#/definitions/adapter" }
    },
    {
      "if": {
        "type": "object",
        "properties": {
          "type": { "const": "server_pid" }
        },
        "required": ["type"]
      },
      "then": { "$ref": "#/definitions/server-pid" }
    }
  ],

Upvotes: 2

Related Questions