0

Based on the given JSON schema, If I have to build "required" for the 'DayActivity' based on the 'Day' selected in DayHeader (e.g Only PhysicalActivity should be required If Day is SUNDAY) , how do i build the JSON schema? I've tried various approaches such if then else and definitions. When I generate JSON file based on the JSON schema, it couldn't validate the required 'DayActivity' selected by the "Day" attribute. Basically how do I refer the value selected in other property and build "required"? Appreciate any reference for this issue.

{
  "$schema": "http://json-schema.org/draft-07/schema#",
  "type": "object",
  "properties": {
    "DayHeader": {
      "$schema": "http://json-schema.org/draft-07/schema#",
      "type": "object",
      "properties": {
        "Day": {
          "type": "string",
          "enum": [
            "SUNDAY",
            "MONDAY",
            "TUESDAY",
            "WEDNESDAY",
            "THURSDAY",
            "FRIDAY",
            "SATURDAY"
          ]
        }
      },
      "required": [
        "day"
      ]
    },
    "ActivityDetail": {
      "$schema": "http://json-schema.org/draft-07/schema#",
      "type": "object",
      "properties": {
        "DayActivity": {
          "type": "array",
          "items": {
            "type": "object",
            "properties": {
              "PhysicalActivity": {
                "type": "string",
                "enum": [
                  "Walking",
                  "Running"
                ]
              },
              "StudyActivity": {
                "type": "string",
                "enum": [
                  "Maths Class",
                  "Science Class"
                ]
              },
              "ArtActivity": {
                "type": "string",
                "enum": [
                  "Drawing",
                  "Dance"
                ]
              }
            }
          }
        }
      }
    }
  }
}
Sahank
  • 1
  • 1
  • Could you maybe provide an example JSON instance where you’d expect the validation to fail? That’d make it a bit easier. Also: be careful with casing. You are defining two properties on the `DayHeader`: “Day” and “day” (via “required”). Is the `DayActivity` also “required” and with a “minItems” of 1 then? Just making the `PhysicalActivity` “required” seems to leave a lot of loopholes allowing to still omit it. Is that intentional or maybe the reason why you don’t get the results you’re looking for. `if`/`then` sound like the right approach. Maybe include your attempt here as well. – Carsten Apr 12 '20 at 11:37
  • You do not need to (and should not) redefine `$schema` at any level other than the root of the schema. – Relequestual Apr 14 '20 at 11:33
  • Does this answer your question? [JSON Schema - conditional validation](https://stackoverflow.com/questions/56424330/json-schema-conditional-validation) – Relequestual Apr 14 '20 at 11:35
  • @Carsten DayActivity needs to have minItems as 1. – Sahank Apr 15 '20 at 20:53
  • @Relequestual Thanks for Sharing. I will try it out and update this thread. – Sahank Apr 15 '20 at 20:53
  • This [answer](https://stackoverflow.com/a/38781027/5127499) seems more comprehensive as it doesn't only focus on `if`/`then`/`else` – Carsten Apr 15 '20 at 20:56
  • Does this answer your question? [jsonSchema attribute conditionally required](https://stackoverflow.com/questions/38717933/jsonschema-attribute-conditionally-required) – Jason Desrosiers Apr 16 '20 at 02:48
  • @JasonDesrosiers I already linked to your excellent answer on that other question. ;) – Carsten Apr 16 '20 at 05:18

1 Answers1

0

Generally speaking, this question already has an awesome generic answer here.

That being said, you might be able to improve your data structure in regards to the "DayActivity", which would also make it easier to formulate the corresponding JSON Schema.


Your "DayActivity" is currently an array of objects, with each object containing up to three properties at the same time: "PhysicalActivity"/"StudyActivity"/"ArtActivity". How about something like the following instead, that only allows one of the three properties to be present in a single array item:

"DayActivity": {
  "type": "array",
  "minItems": 1,
  "items": {
    "type": "object",
    "oneOf": [
      {
        "properties": {
          "PhysicalActivity": {
            "type": "string",
            "enum": ["Walking", "Running"]
          }
        },
        "required": ["PhysicalActivity"]
      },
      {
        "properties": {
          "StudyActivity": {
            "type": "string",
            "enum": ["Maths Class", "Science Class"]
          }
        },
        "required": ["StudyActivity"]
      },
      {
        "properties": {
          "ArtActivity": {
            "type": "string",
            "enum": ["Drawing", "Dance"]
          }
        },
        "required": ["ArtActivity"]
      }
    ]
  },
  "contains": {
    "required": ["PhysicalActivity"]
  }
}

Note the "contains" keyword in the end to ensure that there always needs to be at least one "PhysicalActivity" entry in the "DayActivity" array.

If you now want to conditionally enforce a "StudyActivity" on each weekday but "SUNDAY", you could add the following inside the main schema (i.e. at the top level, where "properties": { "DayHeader": ... } is being declared:

"oneOf": [
  {
    "properties": {
      "DayHeader": {
        "properties": {
          "Day": {
            "const": "SUNDAY"
          }
        }
      }
    }
  },
  {
    "properties": {
      "DayHeader": {
        "properties": {
          "Day": {
            "enum": [
              "MONDAY", "TUESDAY", "WEDNESDAY", "THURSDAY", "FRIDAY", "SATURDAY"
            ]
          }
        }
      },
      "ActivityDetail": {
        "properties": {
          "DayActivity": {
            "contains": {
              "required": ["StudyActivity"]
            }
          }
        }
      }
    }
  }
]

A complete schema could look something like this then:

{
  "$schema": "http://json-schema.org/draft-07/schema#",
  "type": "object",
  "required": ["DayHeader", "ActivityDetail"],
  "properties": {
    "DayHeader": {
      "type": "object",
      "properties": {
        "Day": {
          "type": "string",
          "enum": [
            "SUNDAY",
            "MONDAY",
            "TUESDAY",
            "WEDNESDAY",
            "THURSDAY",
            "FRIDAY",
            "SATURDAY"
          ]
        }
      },
      "required": [
        "Day"
      ]
    },
    "ActivityDetail": {
      "type": "object",
      "required": ["DayActivity"],
      "properties": {
        "DayActivity": {
          "type": "array",
          "minItems": 1,
          "items": {
            "type": "object",
            "oneOf": [
              {
                "properties": {
                  "PhysicalActivity": {
                    "type": "string",
                    "enum": ["Walking", "Running"]
                  }
                },
                "required": ["PhysicalActivity"]
              },
              {
                "properties": {
                  "StudyActivity": {
                    "type": "string",
                    "enum": ["Maths Class", "Science Class"]
                  }
                },
                "required": ["StudyActivity"]
              },
              {
                "properties": {
                  "ArtActivity": {
                    "type": "string",
                    "enum": ["Drawing", "Dance"]
                  }
                },
                "required": ["ArtActivity"]
              }
            ]
          },
          "contains": {
            "required": ["PhysicalActivity"]
          }
        }
      }
    }
  },
  "oneOf": [
    {
      "properties": {
        "DayHeader": {
          "properties": {
            "Day": {
              "const": "SUNDAY"
            }
          }
        }
      }
    },
    {
      "properties": {
        "DayHeader": {
          "properties": {
            "Day": {
              "enum": [
                "MONDAY", "TUESDAY", "WEDNESDAY", "THURSDAY", "FRIDAY", "SATURDAY"
              ]
            }
          }
        },
        "ActivityDetail": {
          "properties": {
            "DayActivity": {
              "contains": {
                "required": ["StudyActivity"]
              }
            }
          }
        }
      }
    }
  ]
}

The above successfully validates against:

{
  "DayHeader": { "Day": "SUNDAY"},
  "ActivityDetail": {
    "DayActivity": [
      { "PhysicalActivity": "Walking" }
    ]
  }
}

But not against the following (because a "StudyActivity" is missing:

{
  "DayHeader": { "Day": "WEDNESDAY"},
  "ActivityDetail": {
    "DayActivity": [
      { "PhysicalActivity": "Walking" }
    ]
  }
}
Carsten
  • 2,047
  • 1
  • 21
  • 46
  • Thanks. I will check this. Right now, I'm using "https://json-schema-faker.js.org/" by inputting the JSON schema and generating the output and found thay it is not generating correctly. Looks like I need to build a JSON schema validator class and passing the json & schema to validate. I will check on this. if possible, let me know how you are validating it. – Sahank Apr 17 '20 at 07:12
  • Thank you. I converted to IF-else structure since I had to add conditions based on the Day header and for many more attributes such as DayActivity is one of the example listed here. I thought of having if-else inside 'DayActivity' would be more easier to understand the schema. I rebuilt it with if-else. Please find my updated one. If I change the DayHeader, it is not validating DayActivity based on the DayHeader. – Sahank Apr 19 '20 at 20:58
  • @Sahank I meant adding your changed schema at the bottom of your question – not to my answer. I had a look at your suggested edit though. You changed the wrong `oneOf`. For these `if`/`then` clauses, you should focus on the `oneOf` at the top-level schema (the one at the bottom of my example here in the answer). – Carsten Apr 19 '20 at 21:15