Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Multiple If-Then-Else not validating for JSON Schema

I have a program that I have built that takes a JSON object and produces a JSON schema file based on the details of the input. When I use this program to generate a schema for a smaller JSON object, the schema works correctly and validates as expected. In this smaller schema there is only one if-then-else block.

However when I attempt to generate a schema that makes use of several if-then-else blocks the if-then-else validation seems to stop working at all and will allow anything through.

I'll post an example below to be more clear.

JSON Schema

{
  "$schema": "http://json-schema.org/draft-07/schema#",
  "definitions": {
    "question6-99": {
      "type": "object",
      "properties": {
        "answer": {
          "type": "string",
          "enum": ["Yes", "No"]
        }
      }
    },
    "question6-100": {
      "type": "object",
      "properties": {
        "answer": {
          "type": "string",
          "enum": ["Mr","Ms","Mrs","Miss","Dr","Rev","Sir","Lady","Lord","Prof", ""]
        }
      }
    }
  },
  "type": "object",
  "properties": {
    "form_submission": {
      "type": "object",
      "properties": {
        "sections": {
          "type": "object",
          "properties": {
            "6": {
              "type": "object",
              "properties": {
                "questions": {
                  "type": "object",
                  "properties": {
                    "99": {
                      "$ref": "#/definitions/question6-99"
                    },
                    "100": {
                      "$ref": "#/definitions/question6-100"
                    }
                  },
                  "if": {
                    "properties": {
                      "99": {
                        "properties": {
                          "answer": {
                            "enum": [
                              "Yes"
                            ]
                          }
                        },
                        "required": [
                          "answer"
                        ]
                      }
                    },
                    "required": [
                      "100"
                    ]
                  },
                  "then": {
                    "properties": {
                      "100": {
                        "properties": {
                          "answer": {
                            "minLength": 1
                          }
                        }
                      }
                    }
                  },
                  "else": {
                    "properties": {
                      "100": {
                        "properties": {
                          "answer": {
                            "maxLength": 0
                          }
                        }
                      }
                    }
                  }
                }
              }
            }
          },
          "required": [
            "6"
          ]
        }
      }
    }
  }
}

JSON Object being validated

{
  "form_submission": {
    "sections": {
      "1": {
        "questions": {
          "99": {
            "answer": "Yes",
          },
          "100": {
            "answer": "",
          }
        }
      }
    }
  }
}

For the above example, if the schema is used to validate the object, the answer for question 100 must be answered when question 99 is answered "yes". This works correctly.

However if I then attempt to use the schema below, which uses two if-then-else blocks against the second JSON object, no if-then-else validation occurs.

I'm just wondering if I have done something wrong with the structure of my schema code that is stopping the validation from happening correctly.

Schema using two If-then-else

{
    "$schema": "http://json-schema.org/draft-07/schema#",
    "definitions": {
        "question6-99": {
            "type": "object",
            "properties": {
                "answer": {
                    "type": "string",
                    "minLength": 1,
                    "enum": ["Yes", "No"]
                }
            }
        },
        "question6-100": {
            "type": "object",
            "properties": {
                "answer": {
                    "type": "string",
                    "enum": ["Mr", "Ms", "Mrs", "Miss", "Dr", "Rev", "Sir", "Lady", "Lord", "Prof", ""]
                }
            }
        },
        "question6-101": {
            "type": "object",
            "properties": {
                "answer": {
                    "type": "string"
                }
            }
        }
    },
    "type": "object",
    "properties": {
        "form_submission": {
            "type": "object",
            "properties": {
                "sections": {
                    "type": "object",
                    "properties": {
                        "6": {
                            "type": "object",
                            "properties": {
                                "questions": {
                                    "type": "object",
                                    "properties": {
                                        "99": {
                                            "$ref": "#/definitions/question6-99"
                                        },
                                        "100": {
                                            "$ref": "#/definitions/question6-100"
                                        },
                                        "101": {
                                            "$ref": "#/definitions/question6-101"
                                        }
                                    },
                                    "required": ["99", "100", "101", "102", "103", "104", "105", "111"],
                                    "if": {
                                        "properties": {
                                            "99": {
                                                "properties": {
                                                    "answer": {
                                                        "enum": ["Yes"]
                                                    }
                                                },
                                                "required": ["answer"]
                                            }
                                        },
                                        "required": ["100"]
                                    },
                                    "then": {
                                        "properties": {
                                            "100": {
                                                "properties": {
                                                    "answer": {
                                                        "minLength": 1
                                                    }
                                                }
                                            }
                                        }
                                    },
                                    "else": {
                                        "properties": {
                                            "100": {
                                                "properties": {
                                                    "answer": {
                                                        "maxLength": 0
                                                    }
                                                }
                                            }
                                        }
                                    },
                                    "if": {
                                        "properties": {
                                            "99": {
                                                "properties": {
                                                    "answer": {
                                                        "enum": ["Yes"]
                                                    }
                                                },
                                                "required": ["answer"]
                                            }
                                        },
                                        "required": ["101"]
                                    },
                                    "then": {
                                        "properties": {
                                            "101": {
                                                "properties": {
                                                    "answer": {
                                                        "minLength": 1
                                                    }
                                                }
                                            }
                                        }
                                    },
                                    "else": {
                                        "properties": {
                                            "101": {
                                                "properties": {
                                                    "answer": {
                                                        "maxLength": 0
                                                    }
                                                }
                                            }
                                        }
                                    }
                                }
                            }
                        }
                    },
                    "required": ["1"]
                }
            }
        }
    }
}

Second schema to validate

{
    "form_submission": {
        "id": "80035",
        "status": "Incomplete",
        "validated": true,
        "failure_reason": "",
        "sections": {

            "1": {
                "questions": {
                    "99": {
                        "answer": "Yes",
                        "web_validated": true,
                        "web_error_string": "",
                        "server_error_string": ""
                    },
                    "100": {
                        "answer": "",
                        "web_validated": true,
                        "web_error_string": "",
                        "server_error_string": ""
                    },
                    "101": {
                        "answer": "Yes",
                        "web_validated": true,
                        "web_error_string": "",
                        "server_error_string": ""
                    }
                },
                "name": "",
                "validated": true,
                "server_validated": true,
                "notes": ""
            }
        },
        "submitted_section_id": 11
    }
}

Added allOf to Schema

{
    "$schema": "http://json-schema.org/draft-07/schema#",
    "definitions": {
        "question6-99": {
            "type": "object",
            "properties": {
                "answer": {
                    "type": "string",
                    "minLength": 1,
                    "enum": ["Yes", "No"]
                }
            }
        },
        "question6-100": {
            "type": "object",
            "properties": {
                "answer": {
                    "type": "string",
                    "enum": ["Mr", "Ms", "Mrs", "Miss", "Dr", "Rev", "Sir", "Lady", "Lord", "Prof", ""]
                }
            }
        },
        "question6-101": {
            "type": "object",
            "properties": {
                "answer": {
                    "type": "string"
                }
            }
        }
    },
    "type": "object",
    "properties": {
        "form_submission": {
            "type": "object",
            "properties": {
                "sections": {
                    "type": "object",
                    "properties": {
                        "6": {
                            "type": "object",
                            "properties": {
                                "questions": {
                                    "type": "object",
                                    "properties": {
                                        "99": {
                                            "$ref": "#/definitions/question6-99"
                                        },
                                        "100": {
                                            "$ref": "#/definitions/question6-100"
                                        },
                                        "101": {
                                            "$ref": "#/definitions/question6-101"
                                        }
                                    },
                                    "required": ["99", "100", "101", "102", "103", "104", "105", "111"],
                                    "allOf": [
                                      {
                                        "if": {
                                            "properties": {
                                                "99": {
                                                    "properties": {
                                                        "answer": {
                                                            "enum": ["Yes"]
                                                        }
                                                    },
                                                    "required": ["answer"]
                                                }
                                            },
                                            "required": ["100"]
                                        },
                                        "then": {
                                            "properties": {
                                                "100": {
                                                    "properties": {
                                                        "answer": {
                                                            "minLength": 1
                                                        }
                                                    }
                                                }
                                            }
                                        },
                                        "else": {
                                            "properties": {
                                                "100": {
                                                    "properties": {
                                                        "answer": {
                                                            "maxLength": 0
                                                        }
                                                    }
                                                }
                                            }
                                        }},
                                      {
                                        "if": {
                                            "properties": {
                                                "99": {
                                                    "properties": {
                                                        "answer": {
                                                            "enum": ["Yes"]
                                                        }
                                                    },
                                                    "required": ["answer"]
                                                }
                                            },
                                            "required": ["101"]
                                        },
                                        "then": {
                                            "properties": {
                                                "101": {
                                                    "properties": {
                                                        "answer": {
                                                            "minLength": 1
                                                        }
                                                    }
                                                }
                                            }
                                        },
                                        "else": {
                                            "properties": {
                                                "101": {
                                                    "properties": {
                                                        "answer": {
                                                            "maxLength": 0
                                                        }
                                                    }
                                                }
                                            }
                                        }
                                      }
                                    ]
                                }
                            }
                        }
                    },
                    "required": ["1"]
                }
            }
        }
    }
}
like image 417
Jake12342134 Avatar asked Dec 04 '22 18:12

Jake12342134


1 Answers

If we remove the complicated bits, I think the problem becomes clear.

{
  "if": { ... },
  "then": { ... },
  "if": { ... },
  "then": { ... }
}

In JSON the value of duplicated keys is undefined. One of these ifs and one of these thens will be ignored by a JSON parser.

You can get around this problem by wrapping your ifs in an allOf.

{
  "allOf": [
    {
      "if": { ... },
      "then": { ... }
    },
    {
      "if": { ... },
      "then": { ... }
    }
  ]
}

It's good practice to always wrap your if/then/else in allOf even if you have only one. This is because a JSON object is by definition unordered. Therefore, some tool might rearrange your keywords splitting up the ifs and thens in a way that makes the schema difficult to decipher.

{
  "definitions": {},
  "else": {},
  "if": {},
  "properties": {},
  "then": {},
  "type": "object",
}
like image 133
Jason Desrosiers Avatar answered Dec 09 '22 14:12

Jason Desrosiers