Использовать json-схему, чтобы требовать или запрещать свойства на основе другого значения свойства?

То, что я пытаюсь выполнить в json-схеме: когда свойство enabled равно true, должны потребоваться некоторые другие свойства. Когда false, эти свойства следует запретить.

Вот моя json-схема:

{
  "type": "object",
  "properties": {
    "enabled": { "type": "boolean" }
  },
  "required" : ["enabled"],
  "additionalProperties" : false,
  "if": {
    "properties": {
      "enabled": true
    }
  },
  "then": { 
    "properties": {
      "description" : { "type" : "string" },
      "count": { "type": "number" }
    },
    "required" : ["description", "count"]
  }
}

При проверке с использованием ajv версии 6.5 это привело к требованию count и т. Д. Независимо от значения enabled. Например, для данных:

{ "enabled": false }

Мои ошибки проверки:

[ { keyword: 'required',
    dataPath: '',
    schemaPath: '#/then/required',
    params: { missingProperty: 'description' },
    message: 'should have required property \'description\'' },
  { keyword: 'required',
    dataPath: '',
    schemaPath: '#/then/required',
    params: { missingProperty: 'count' },
    message: 'should have required property \'count\'' },
  { keyword: 'if',
    dataPath: '',
    schemaPath: '#/if',
    params: { failingKeyword: 'then' },
    message: 'should match "then" schema' } ]

Как это сделать с помощью json-schema draft-7?

Обратите внимание, что этот вопрос похож на, но имеет более строгие требования, чем:
условно обязательный атрибут jsonSchema.


person Clay Bridges    schedule 15.05.2018    source источник
comment
Возможный дубликат атрибута условно обязательного атрибута jsonSchema   -  person Jason Desrosiers    schedule 15.05.2018
comment
@ Джейсон Не дубликат. Аналогично, но к этому вопросу предъявляются более строгие требования.   -  person Clay Bridges    schedule 15.05.2018
comment
Я не согласен. Это довольно простой вариант использования стратегии Enum. Фактически, ваш ответ ниже использует эту стратегию. Ваш ответ должен быть отмечен как принятый. Это намного лучше, чем ответ _1 _-_ 2 _-_ 3_.   -  person Jason Desrosiers    schedule 16.05.2018
comment
Я согласен принять свой ответ (через 5 часов), потому что это, вероятно, более элегантное решение моей проблемы. Я утверждаю, что этот вопрос не повторяется, потому что он задает другой, если он связан, вопрос. Я не раз читал ваш (отличный) ответ на другой вопрос и до сих пор не знал, как решить мою / эту конкретную проблему. Хотя применимость варианта стратегии Enum здесь может быть очевидна для опытного специалиста, как новичок я могу сказать, что для меня это было не очевидно. Лучше, чтобы это было подробно описано для этого случая, чтобы, возможно, спасти других, которые борются.   -  person Clay Bridges    schedule 16.05.2018


Ответы (3)


Попробуйте эту схему:

{
  "type": "object",
  "properties": {
    "enabled": {
      "type": "boolean"
    }
  },
  "required": [
    "enabled"
  ],
  "if": {
    "properties": {
      "enabled": {
        "const": true
      }
    }
  },
  "then": {
    "properties": {
      "enabled": {
        "type": "boolean"
      },
      "description": {
        "type": "string"
      },
      "count": {
        "type": "number"
      },
      "additionalProperties": false
    },
    "required": [
      "description",
      "count"
    ]
  },
  "else": {
    "properties": {
      "enabled": {
        "type": "boolean"
      }
    },
    "additionalProperties": false
  }
}

Если вам нужно "additionalProperties": false, вы должны перечислить все свойства как в then, так и в else. Если вы можете принять дополнительные свойства, схема может быть проще:

{
  "type": "object",
  "properties": {
    "enabled": {
      "type": "boolean"
    }
  },
  "required": [
    "enabled"
  ],
  "if": {
    "properties": {
      "enabled": {
        "const": true
      }
    }
  },
  "then": {
    "properties": {
      "description": {
        "type": "string"
      },
      "count": {
        "type": "number"
      }
    },
    "required": [
      "description",
      "count"
    ]
  }
}

Я проверил с помощью ajv cli.

Действителен: {"enabled": false}

Недействительно: {"enabled": true}

Действителен: {"enabled": true, "description":"hi", "count":1}

person vearutop    schedule 15.05.2018

Это было вдохновлено отличным ответом vearutop. Я думаю, что это могло бы быть немного короче и выполняет мою заявленную цель.

{
  "type": "object",
  "oneOf" : [
    {
      "properties": {
        "enabled": { "const": false }
      },
      "required": ["enabled"],
      "additionalProperties": false
    },
    {
      "properties": {
        "enabled": { "const": true },
        "description": { "type": "string" },
        "count": { "type": "number" }
      },
      "required": [ "enabled", "description", "count"],
      "additionalProperties": false
    }
  ]
}

Как указано в комментариях, это конкретный вариант стратегии Enum, изложенный в этом ответе .

person Clay Bridges    schedule 15.05.2018

Для этого в операторе if необходимо использовать ключевое слово const, поэтому схема будет выглядеть так:

{
  "type": "object",
  "properties": {
    "enabled": { "type": "boolean" }
  },
  "required" : ["enabled"],
  "additionalProperties" : false,
  "if": {
    "properties": {
      "enabled": {"const": true}
    }
  },
  "then": { 
    "properties": {
      "description" : { "type" : "string" },
      "count": { "type": "number" }
    },
    "required" : ["description", "count"]
  }
}
person fpenim    schedule 01.06.2018