rjsf-team / react-jsonschema-form

A React component for building Web forms from JSON Schema.
https://rjsf-team.github.io/react-jsonschema-form/
Apache License 2.0
14.1k stars 2.18k forks source link

Issue with oneOf Validation in rjsf #4252

Open dmistry1 opened 1 month ago

dmistry1 commented 1 month ago

Prerequisites

What theme are you using?

validator-ajv8

What is your question?

I'm working with a schema that uses the oneOf keyword to define two options, each with its own set of required fields. However, I'm encountering an issue where, after selecting one option and entering values, the validator incorrectly prompts for required fields from the other option.

Here’s a simplified example of my schema:

{
  "oneOf": [
    {
      "type": "object",
      "properties": {
        "optionAField1": { "type": "string" },
        "optionAField2": { "type": "number" }
      },
      "required": ["optionAField1"]
    },
    {
      "type": "object",
      "properties": {
        "optionBField1": { "type": "string" },
        "optionBField2": { "type": "number" }
      },
      "required": ["optionBField1"]
    }
  ]
}

When I select the first option and fill in optionAField1, I receive a validation error indicating that optionBField1 is required, even though it should not be necessary for the chosen option.

Is this a known issue with rjsf, or am I missing something in my schema configuration? How can I resolve this issue?

nickgros commented 1 month ago

@dmistry1 can you double-check your schema & reproduction steps? I am trying to use your schema in the Playground here, and I can submit the data without errors

dmistry1 commented 1 month ago

@nickgros Taking the playground that you provided as an example, say a user fills out optionAField2 field which is not required and we call validate. In the screenshot that I have attached, we can see that we get an error must have required property 'optionBField1' even though we selected Option 1. image

nickgros commented 1 month ago

With your schema, Ajv has no idea whether you picked 'Option 1' or 'Option 2'. That's entirely a UI construct. If you want Ajv to 'know' about the chosen option, you need to encode that choice into the schema. To do that you have a few options.

If/then/else

You could use "if"/"then"/"else" conditions in your schema so only certain subschemas are validated when the choice matches a certain value. See this example. Basically, your optionA subschema is only loaded when the formData option matches the chosen value.

Discriminator

We have some basic support for the OpenAPI discriminator keyword. Unfortunately we don't have many docs that describe how to use this, and actual Ajv support is a bit spotty. @heath-freenome and I had some luck transcribing your schema into the following example, and modifying the Ajv instance to enable discriminator support. We don't have a way to test this in the playground, so if you want to try this you will have to test it on your machine or in something like CodeSandbox.

{
  "type": "object",
  "definitions": {
    "OptionA": {
      "type": "object",
      "properties": {
        "option": {
          "type": "string",
          "default": "optionA",
          "enum": [
            "optionA"
          ]
        },
        "optionAField1": {
          "type": "string"
        },
        "optionAField2": {
          "type": "number"
        }
      },
      "required": [
        "optionAField1"
      ]
    },
    "OptionB": {
      "type": "object",
      "properties": {
        "option": {
          "type": "string",
          "default": "optionB",
          "enum": [
            "optionB"
          ]
        },
        "optionBField1": {
          "type": "string"
        },
        "optionBField2": {
          "type": "number"
        }
      },
      "required": [
        "optionAField1"
      ]
    }
  },
  "discriminator": {
    "propertyName": "option"
  },
  "oneOf": [
    {
      "$ref": "#/definitions/OptionA"
    },
    {
      "$ref": "#/definitions/OptionB"
    }
  ],
  "required": [
    "option"
  ]
}
nickgros commented 1 month ago

@heath-freenome added an option to the playground to test validation with an Ajv instance where the discriminator option is true.

@dmistry1 here's a playground example of the discriminator suggestion. Change the "Validator" option to "AJV 8 (discriminator)"

dmistry1 commented 1 month ago

@nickgros thank you so much for this information.