Атрибут jsonSchema условно необходим

В jsonSchema вы можете указать, являются ли определенные поля обязательными или нет, используя атрибут "required":

{
    "$schema": "http://json-schema.org/draft-04/schema#",
    "type": "object",
    "properties": {
        "header": {
            "type": "object",
            "properties": {
                "messageName": {
                    "type": "string"
                },
                "messageVersion": {
                    "type": "string"
                }
            },
            "required": [
                "messageName",
                "messageVersion"
            ]
        }
    },
    "required": [
        "header"
    ]
}

В некоторых случаях я бы хотел, чтобы поле messageVersion не было обязательным. Есть ли способ сделать обязательное условие этого поля условным?

Ответ 1

В зависимости от вашей ситуации, есть несколько разных подходов. Я могу придумать четыре разных способа условно требовать поле.

зависимости

Ключевое слово dependencies является условным вариантом ключевого слова required. Свойство Foreach в dependencies, если свойство присутствует в проверяемом JSON, то схема, связанная с этим ключом, также должна быть действительной. Если присутствует свойство "foo", то требуется свойство "bar"

{
  "type": "object",
  "properties": {
    "foo": { "type": "string" },
    "bar": { "type": "string" }
  },
  "dependencies": {
    "foo": { "required": ["bar"] }
  }
}

Существует также краткая форма, если схема содержит только ключевое слово required.

{
  "type": "object",
  "properties": {
    "foo": { "type": "string" },
    "bar": { "type": "string" }
  },
  "dependencies": {
    "foo": ["bar"]
  }
}

Причастность

Если ваше условие зависит от значения поля, вы можете использовать булеву логику, называемую импликацией. "Подразумевает, что B" означает, что если A истинно, то B также должно быть истинно. Значение также может быть выражено как "! A или B". Либо свойство "foo" не равно "bar", либо требуется свойство "bar". Или, другими словами: Если свойство "foo" равно "bar", то требуется свойство "bar"

{
  "type": "object",
  "properties": {
    "foo": { "type": "string" },
    "bar": { "type": "string" }
  },
  "anyOf": [
    {
      "not": {
        "properties": {
          "foo": { "const": "bar" }
        },
        "required": ["foo"]
      }
    },
    { "required": ["bar"] }
  ]
}

Если "foo" не равно "bar", #/anyOf/0 совпадает и проверка успешна. Если "foo" равно "bar", #/anyOf/0 завершается ошибкой и #/anyOf/1 должен быть действительным, чтобы проверка anyOf была успешной.

Enum

Если ваше условное выражение основано на перечислении, оно немного более прямолинейно. "foo" может быть "bar" или "baz". Если "foo" равно "bar", то требуется "bar". Если "foo" равно "baz", то требуется "baz".

{
  "type": "object",
  "properties": {
    "foo": { "enum": ["bar", "baz"] },
    "bar": { "type": "string" },
    "baz": { "type": "string" }
  },
  "anyOf": [
    {
      "properties": {
        "foo": { "const": "bar" }
      },
      "required": ["bar"]
    },
    {
      "properties": {
        "foo": { "const": "baz" }
      },
      "required": ["baz"]
    }
  ]
}

If-Then-Else

Относительно новое дополнение к JSON Schema (draft-07) добавляет ключевые слова if, then и else. Если свойство "foo" равно "bar", то свойство "bar" обязательно

{
  "type": "object",
  "properties": {
    "foo": { "type": "string" },
    "bar": { "type": "string" }
  },
  "if": {
    "properties": {
      "foo": { "const": "bar" }
    },
    "required": ["foo"]
  },
  "then": { "required": ["bar"] }
}

ОБНОВЛЕНИЕ 23.12.2017: Обновлен раздел импликации и добавлен раздел If-Then-Else.

ОБНОВЛЕНИЕ 04/04/2018: Исправление для If-Then-Else и обновление синглтона enum для использования const.