1
votes

I have a Json request having the below data and a corresponding json schema for it

With this request, I want to make a few fields as required depending on the mode

Say if mode is 1, then I want the fields a and b in obj1 to be required and field x in obj3 as required. Now if the mode is 2, I would want fields p, q and r in obj2 to be required, fields a and c in obj1 as required and field y in obj3 as required. Next if the mode is 3, I want only fields a and c as required

Json request

{
  "mode": "1",
  "obj1": {
      "a": 12,
      "b": "test",
      "c": "18 June 2019"
      },
 "obj2": {
      "p": 100,
      "q": "new",
      "r": "19 June 2019",
      "s" : "test2"
      },
  "obj3": {
      "x": 12,
      "y": "test3"
      }
}


**Json schema**
{
  "definitions": {},
  "$schema": "http://json-schema.org/draft-07/schema#",
  "$id": "http://example.com/root.json",
  "type": "object",
  "properties": {
    "mode": {
      "$id": "#/properties/mode",
      "type": "string",
      "examples": [
        "1"
      ]
    },
    "obj1": {
      "$id": "#/properties/obj1",
      "type": "object",
      "title": "The Obj 1 Schema",
      "properties": {
        "a": {
          "$id": "#/properties/obj1/properties/a",
          "type": "integer",
          "examples": [
            12
          ]
        },
        "b": {
          "$id": "#/properties/obj1/properties/b",
          "type": "string",
          "examples": [
            "test"
          ]
        },
        "c": {
          "$id": "#/properties/obj1/properties/c",
          "type": "string",
          "examples": [
            "18 June 2019"
          ]
        }
      }
    },
    "obj 2": {
      "$id": "#/properties/obj2",
      "type": "object",
      "title": "The Obj 2 Schema",
      "properties": {
        "p": {
          "$id": "#/properties/obj2/properties/p",
          "type": "integer",
          "examples": [
            100
          ]
        },
        "q": {
          "$id": "#/properties/obj2/properties/q",
          "type": "string",
          "examples": [
            "new"
          ]
        },
        "r": {
          "$id": "#/properties/obj2/properties/r",
          "type": "string",
          "examples": [
            "19 June 2019"
          ]
        },
        "s": {
          "$id": "#/properties/obj2/properties/s",
          "type": "string",
          "examples": [
            "test2"
          ]
        }
      }
    },
    "obj 3": {
      "$id": "#/properties/obj3",
      "type": "object",
      "title": "The Obj 3 Schema",
      "properties": {
        "x": {
          "$id": "#/properties/obj3/properties/x",
          "type": "integer",
          "examples": [
            12
          ]
        },
        "y": {
          "$id": "#/properties/obj3/properties/y",
          "type": "string",
          "examples": [
            "test3"
          ]
        }
      }
    }
  }
}

EDIT - Changed the schema to validate based on the suggestion by @gregsdennis

JSON SCHEMA

    {
      "definitions": {},
      "$schema": "http://json-schema.org/draft-07/schema#",
      "$id": "http://example.com/root.json",
      "type": "object",
      "properties": {
        "mode": {
          "$id": "#/properties/mode",
          "type": "string",
          "examples": [
            "1"
          ]
        },
        "obj1": {
          "$id": "#/properties/obj1",
          "type": "object",
          "title": "The Obj 1 Schema",
          "properties": {
            "a": {
              "type": "integer",
              "examples": [
                12
              ]
            },
            "b": {
              "type": "string",
              "examples": [
                "test"
              ]
            },
            "c": {
              "type": "string",
              "examples": [
                "18 June 2019"
              ]
            }
          }
        },
        "obj 2": {
          "$id": "#/properties/obj2",
          "type": "object",
          "title": "The Obj 2 Schema",
          "properties": {
            "p": {
              "type": "integer",
              "examples": [
                100
              ]
            },
            "q": {
              "type": "string",
              "examples": [
                "new"
              ]
            },
            "r": {
              "type": "string",
              "examples": [
                "19 June 2019"
              ]
            },
            "s": {
              "type": "string",
              "examples": [
                "test2"
              ]
            }
          }
        },
        "obj 3": {
          "$id": "#/properties/obj3",
          "type": "object",
          "title": "The Obj 3 Schema",
          "properties": {
            "x": {
              "type": "integer",
              "examples": [
                12
              ]
            },
            "y": {
              "type": "string",
              "examples": [
                "test3"
              ]
            }
          }
        }
      },
"oneOf": [
    {
      "properties": {
        "mode": {"const": 1},
        "obj1": {"required": ["a","b"]},
        "obj3": {"required": ["x"]}
       }
    },
    {
      "properties": {
        "mode": {"const": 2},
        "obj2": {"required": ["p","q","r"]},
        "obj1": {"required": ["a","c"]},
        "obj3": {"required": ["y"]}
       }
    }
]
    }

So, in brief, irrespective of how many modes, fields or objects I have, I would like only a few selected fields from different objects to be required at a given time for a particular mode. Can anyone please suggest any solutions to achieve this? Is it possible to have such validations in the json schema?

1

1 Answers

1
votes

What you want is an oneOf where each subschema gives a valid state for each of obj* properties. Each state would be something like this:

{
  "properties": {
    "mode": {"const": 1},
    "obj1": {"required": ["a","b"]},
    "obj3": {"required": ["x"]}
  }
}

Create one of these for each of the states you listed in your question, and throw them all in a oneOf that lives at the root.

You could do this with if/then/else, but for this case, I'd prefer the oneOf to avoid nesting.


Also, I notice that you have a lot of superfluous $ids in the middle that are just specifying their location within the schema. You want the one at the root, but you don't need the others. Implementations can work out these kinds of location-based references trivially.