Removing the duplication in a JSON schema that use

2019-07-23 13:49发布

问题:

I have a set of 2 properties that are always optional, but should only be allowed to be present if the value of another (always required) boolean property is true.

The properties which are always optional, but not always allowed are named: max_recurrences and recurrence_arguments. The boolean property whose value of true that they depend on is named: recurring.

I've come up with the schema below, which I think works, but I'm duplicating all of the other properties in each item of the oneOf array. I'm looking for a way to avoid this duplication.

{
  "id": "plan_schedule",
  "type": "object",
  "oneOf": [
    {
      "properties": {
        "start_date": {
          "type": "string",
          "format": "date-time"
        },
        "end_date": {
          "type": "string",
          "format": "date-time"
        },
        "trigger": {
          "$ref": "re_non_empty_string"
        },
        "arguments": {
          "type": "object",
          "minProperties": 1
        },
        "recurring": {
          "type": "boolean",
          "enum": [true],
        },
        "max_recurrences": {
          "type": "integer",
          "minimum": 1
        },
        "recurrence_arguments": {
          "type": "object",
          "minProperties": 1
        }
      }
    },
    {
      "properties": {
        "start_date": {
          "type": "string",
          "format": "date-time"
        },
        "end_date": {
          "type": "string",
          "format": "date-time"
        },
        "trigger": {
          "$ref": "re_non_empty_string"
        },
        "arguments": {
          "type": "object",
          "minProperties": 1
        },
        "recurring": {
          "type": "boolean",
          "enum": [false],
        },
      }
    }
  ],
  "additionalProperties": false,
  "required": ["start_date", "trigger", "recurring"]
}

Can anyone help me out? I'd like to use v4, but I'm open to using v5 if it helps.

To clarify further, I'm hoping to only have to list the properties: start_date, end_date, trigger and arguments one time in the entire schema.

回答1:

JSON Schema draft-04:

{
  "type": "object",
  "properties": {
    "recurring": {
      "type": "boolean"
    }
    // all other properties
  }
  "additionalProperties": false,
  "required": ["start_date", "trigger", "recurring"]
  "anyOf": [
    {
      "properties": { "recurring": { "enum": [true] } }
    },
    {
      "properties": { "recurring": { "enum": [false] } },
      "not": {
        "anyOf": [
          { "required": ["max_recurrences"] },
          { "required": ["recurrence_arguments"] }
        }
      }
    }
  ]
}

If you use Ajv (I assume so because v5 is the concept not used anywhere else) you can simplify the above using custom keywords "if/then/else" and "prohibited" that are proposed for draft-07 and have some support - they are defined in ajv-keywords. "anyOf" can be replaced with:

"if": { "properties": { "recurring": { "enum": [false] } } },
"then": { "prohibited": ["max_recurrences", "recurrence_arguments"] }

EDIT:

Actually, it can be done even simpler with "dependencies" keyword without any custom keywords. Instead of "anyOf":

"dependencies": {
  "max_recurrences": { "$ref": "#recurring" },
  "recurrence_arguments": { "$ref": "#recurring" }
},
"definitions": {
  "recurring": {
    "id": "#recurring",
    "properties": {
      "recurring": { "enum": [true] }
    }
  }
}