django-jsonform icon indicating copy to clipboard operation
django-jsonform copied to clipboard

Issue with errors for fields inside an anyOf schema not displaying correctly

Open trumpet2012 opened this issue 1 year ago • 4 comments

Hi!

Want to start by saying thanks for writing and maintaining this package.

I noticed an issue with handling validation errors for values inside a anyOf (and likely oneOf) not being surfaced as expected. If you have any anyOf that further down contains a number field with a minimum set, instead of getting back an error message on the number field when you enter a value below the minimum, you get a generic error saying "Some required fields are missing" above the django field.

An example schema to reproduce this below:

{
    "type": "object",
    "properties": {
        "add": {
            "type": "array",
            "items": {
                "anyOf": [
                    {
                        "type": "object",
                        "keys": {
                            "length": {
                                "type": "number",
                                "exclusiveMinimum": 0,
                                "title": "Length (in)"
                            },
                            "width": {
                                "type": "number",
                                "exclusiveMinimum": 0,
                                "title": "Width (in)"
                            },
                            "height": {
                                "type": "number",
                                "exclusiveMinimum": 0,
                                "title": "Height (in)"
                            }
                        },
                        "required": ["length", "width", "height"]
                    },
                    {
                        "type": "object",
                        "keys": {
                            "length": {
                                "type": "number",
                                "exclusiveMinimum": 0,
                                "title": "Length (in)"
                            },
                            "diameter": {
                                "type": "number",
                                "exclusiveMinimum": 0,
                                "title": "Diameter (in)"
                            }
                        },
                        "required": ["length", "diameter"]
                    }
                ]
            }
        }
    }
}

I looked into the JSONSchemaValidator and believe I have identified why this is happening. Looking at the implementation of validate_anyOf (this also applies to oneOf equivalent) it is relying on the possible subschemas validate functions to not raise an exception if the schema matches the data. However if you have min/max rules on some fields in the subschema it will raise the same exception making the anyOf check think that the schema isn't a match. Then once it loops through all of the possible subschemas and doesn't find a match it raises the "Some required fields are missing" exception.

In the meantime my workaround is to implement a custom validator to handle these minimum value checks.

trumpet2012 avatar Mar 08 '24 21:03 trumpet2012

The validator can't know which subschema the user has selected (because that info is UI related and is never transferred to the backend). So we have to loop over all the subschemas to try and find a match for the given data.

We probably need a better way to find a match.

bhch avatar Mar 13 '24 03:03 bhch

Maybe adding support to something similar OpenAPI discriminator could help here. That combined with const and widget: hidden should be enough to help finding which subschema to validate against.

rafa-camargo avatar Sep 09 '24 11:09 rafa-camargo

@rafa-camargo I like this idea. Though I do have a question: Does it only work with object subschemas? What happens when anyOf has array subschemas?

bhch avatar Sep 16 '24 04:09 bhch

From the spec it only applies to object types. But that covers almost all cases no? From JSON's perspective, subclassing array, integer, boolean, doesn't make much sense, right?

What would be a case to use anyOf and array + another type? Could you please give me an example?

rafa-camargo avatar Sep 16 '24 09:09 rafa-camargo