How to allow one property only if other is not present and allow any of other propeties in json schema

烈酒焚心 提交于 2020-01-05 13:09:46

问题


I have six properties: name, age, phone, deletePhone, address, deleteAddress.

I want to create schema that allows anyOf above properties but phone should not be present with deletePhone and address should not be present with deleteAddress(and vice versa).

I have tried this schema:

{
    "type": "object",
    "properties": {
      "name": {
        "type": "string"
      },
      "age": {
        "type": "number"
      },
      "phone": {
        "type": "number"
      },
      "deletePhone": {
        "type": "boolean"
      },
      "address": {
        "type": "string"
      },
      "deleteAddress": {
        "type": "boolean"
      }
    },
    "allOf": [
      {
        "oneOf": [
          {
            "required": ["phone"]
          },
          {
            "required": ["deletePhone"]
          }
        ]
      },
      {
        "oneOf": [
          {
            "required": ["address"]
          },
          {
            "required": ["deleteAddress"]
          }
        ]
      }
    ]
}

It validates true

{
    "name": "my name",
    "address": "some addr",
    "phone": 34
}

and validates false for

{
    "address": "some addr",
    "phone": 34,
    "deletePhone": true
}

which is correct but it also validates false for

{
    "phone": 34
}
or
{
    "name": "some name"
}

Which i want to validate true, i know i'm missing some combination of anyOf, oneOf, Or is there any better way?


回答1:


I think this is the simplest solution.

{
  "type": "object",
  "properties": {
    "name": { "type": "string" },
    "age": { "type": "number" },
    "phone": { "type": "number" },
    "deletePhone": { "type": "boolean" },
    "address": { "type": "string" },
    "deleteAddress": { "type": "boolean" }
  },
  "allOf": [
    { "not": { "required": ["phone", "deletePhone"] } },
    { "not": { "required": ["address", "deleteAddress"] } }
  ]
}



回答2:


EDIT: A different but more reliable and compact approach.

{
  "type": "object",
  "properties": {
    "name": {"type": "string"},
    "age": {"type": "number"},
    "phone": {"type": "number"},
    "deletePhone": {"type": "boolean"},
    "address": {"type": "string"},
    "deleteAddress": {"type": "boolean"}
  },
  "additionalProperties": false,
  "allOf": [
    {
      "oneOf": [
        {
          "allOf": [
            {"required": ["phone"]},
            {"not":{"required":["deletePhone"]}}
          ]
        },
        {
          "allOf": [
            {"required": ["deletePhone"]},
            {"not":{"required":["phone"]}}
          ]
        },
        {
          "allOf": [
            {"not":{"required": ["deletePhone"]}},
            {"not":{"required":["phone"]}}
          ]
        }
      ]
    },
    {
      "oneOf": [
        {
          "allOf": [
            {"required": ["address"]},
            {"not":{"required":["deleteAddress"]}}
          ]
        },
        {
          "allOf": [
            {"required": ["deleteAddress"]},
            {"not":{"required":["address"]}}
          ]
        },
        {
          "allOf": [
            {"not":{"required": ["deleteAddress"]}},
            {"not":{"required":["address"]}}
          ]
        }
      ]
    }
  ]
}

Tested with ajv: https://runkit.com/embed/5qwkquyweir2


OLD (not working):

If you can allow null value to be equal to property not present, the schema could be that simple:

{
  "type": "object",
  "properties": {
    "name": {"type": "string"},
    "age": {"type": "number"}
  },
  "allOf": [
    {
      "oneOf": [
        {
          "properties": {
            "phone": {"type": "number"},
            "deletePhone": {"type": "null"}
          },
          "required": ["phone"]
        },
        {
          "properties": {
            "phone": {"type": "null"},
            "deletePhone": {"type": "boolean"}
          },
          "required": ["deletePhone"]
        },
        {}
      ]
    },
    {
      "oneOf": [
        {
          "properties": {
            "address": {"type": "string"},
            "deleteAddress": {"type": "null"}
          },
          "required": ["address"]
        },
        {
          "properties": {
            "address": {"type": "null"},
            "deleteAddress": {"type": "boolean"}
          },
          "required": ["deleteAddress"]
        },
        {}
      ]
    }
  ]
}

But if you can not allow {"deletePhone":null,"phone":123} schema is more complicated and repeated:

{
  "type": "object",
  "properties": {
    "name": {"type": "string"},
    "age": {"type": "number"}
  },
  "allOf": [
    {
      "oneOf": [
        {
          "properties": {
            "name": {},
            "age": {},
            "address": {},
            "deleteAddress": {},
            "phone": {"type": "number"}
          },
          "required": ["phone"],
          "additionalProperties": false
        },
        {
          "properties": {
            "name": {},
            "age": {},
            "address": {},
            "deleteAddress": {},
            "deletePhone": {"type": "boolean"}
          },
          "required": ["deletePhone"],
          "additionalProperties": false
        },
        {}
      ]
    },
    {
      "oneOf": [
        {
          "properties": {
            "name": {},
            "age": {},
            "phone": {},
            "deletePhone": {},
            "address": {"type": "string"}
          },
          "required": ["address"],
          "additionalProperties": false
        },
        {
          "properties": {
            "name": {},
            "age": {},
            "phone": {},
            "deletePhone": {},
            "deleteAddress": {"type": "boolean"}
          },
          "required": ["deleteAddress"],
          "additionalProperties": false
        },
        {}
      ]
    }
  ]
}



回答3:


Below schema works with all cases but it is lengthy.

{
  "type": "object",
    "oneOf": [
      {
        "anyOf": [
          {
            "oneOf": [
              {
                "properties": {
                  "phone": {
                    "type": "number"
                  },
                  "address": {
                    "type": "string"
                  },
                  "deleteAddress": {
                    "type": "boolean"
                  }
                },
                "required": [
                  "phone"
                ],
                "not": {
                  "required": [
                    "deletePhone"
                  ]
                }
              },
              {
                "properties": {
                  "deletePhone": {
                    "type": "boolean"
                  },
                  "address": {
                    "type": "string"
                  },
                  "deleteAddress": {
                    "type": "boolean"
                  }
                },
                "required": [
                  "deletePhone"
                ],
                "not": {
                  "required": [
                    "phone"
                  ]
                }
              },
              {
                "oneOf": [
                  {
                    "required": [
                      "phone",
                      "address",
                      "deleteAddress"
                    ]
                  },
                  {
                    "required": [
                      "deletePhone",
                      "address",
                      "deleteAddress"
                    ]
                  }
                ]
              }
            ]
          },
          {
            "oneOf": [
              {
                "properties": {
                  "address": {
                    "type": "string"
                  },
                  "phone": {
                    "type": "number"
                  },
                  "deletePhone": {
                    "type": "boolean"
                  }
                },
                "required": [
                  "address"
                ],
                "not": {
                  "required": [
                    "deleteAddress"
                  ]
                }
              },
              {
                "properties": {
                  "deleteAddress": {
                    "type": "boolean"
                  },
                  "phone": {
                    "type": "number"
                  },
                  "deletePhone": {
                    "type": "boolean"
                  }
                },
                "required": [
                  "deleteAddress"
                ],
                "not": {
                  "required": [
                    "address"
                  ]
                }
              },
              {
                "oneOf": [
                  {
                    "required": [
                      "address",
                      "phone",
                      "deletePhone"
                    ]
                  },
                  {
                    "required": [
                      "deleteAddress",
                      "phone",
                      "deletePhone"
                    ]
                  }
                ]
              }
            ]
          }
        ]
      },
      {
        "properties": {
          "name": {
            "type": "string"
          },
          "age": {
            "type": "number"
          }
        },
        "additionalProperties": false
      }
    ]
}


来源:https://stackoverflow.com/questions/50968780/how-to-allow-one-property-only-if-other-is-not-present-and-allow-any-of-other-pr

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!