Условный тип собственности - PullRequest
0 голосов
/ 17 июня 2020

Как я могу создать схему JSON, которая имеет условный тип свойства, основанный на значении другого свойства.

У меня есть это:

    { // Header info removed for brevity
      "definitions": {
        "payloadTypeA": {
          "type": "object",
          "properties": {
            "requestType": {"type": "string","enum": ["A1", "A2"]}},
        },
        "payloadTypeB": {
          "type": "object",
          "properties": {
            "requestType": {"type": "string","enum": ["B1","B2"]}}
        }
      },
      "type": "object",
      "properties": {
        "workload": {
          "type": "string",
          "enum": ["A","B"]
        },
        "payload": {
          "oneOf": [
            {
              "if": {"properties": {"workload": {"const": "A"}}},
              "then": {"$ref": "#/definitions/payloadTypeA"}},
            {
              "if": {"properties": {"workload": {"const": "B"}}},
              "then": {"$ref": "#/definitions/payloadTypeB"}}
          ]
        }
      }
    }

Я ожидаю, что это будет использовать PayloadTypeA, когда значение workload равно «A», и PayloadTypeB, когда workload равно «B». Тем не менее, это проверяет:

{
  "workload": "B",
  "payload": {
    "requestType": "A1",
  }
}

Это также проверяет:

{
  "workload": "B",
  "payload": {
    "requestType": "B1",
  }
}

Но это не так:

{
  "workload": "B",
  "payload": {
    "requestType": "C1",
  }
}

Таким образом, похоже, что это проверяет либо схема полезной нагрузки, независимо от значения рабочей нагрузки.

У меня есть другие условия для значений рабочей нагрузки, поэтому я не могу использовать только простой if/then/else, поскольку у меня будет большая вложенная структура if/then/else, которая было бы кошмаром поддерживать.

1 Ответ

2 голосов
/ 18 июня 2020

У вас есть пара проблем. Начнем с упрощенной версии части вашей схемы.

"properties": {
  "workload": { "enum": ["A","B"] },
  "payload": {
    "if": { "properties": { "workload": { "const": "A" } } },
    "then": { "$ref": "#/definitions/payloadTypeA" }
  }
}

Когда вы помещаете здесь схему if, свойство «рабочая нагрузка» ожидается под свойством «полезная нагрузка», а не на верхнем уровне . Это сработало бы, если бы вы проверяли структуру, которая выглядела так.

{
  "payload": {
    "workload": "B",
    "requestType": "B1",
  }
}

Чтобы заставить это работать, вы должны вытащить блок if / then на более высокий уровень схемы. где у него есть доступ к свойству "рабочая нагрузка".

"properties": {
  "workload": { "enum": ["A","B"] }
},
"if": { "properties": { "workload": { "const": "A" } } },
"then": { "properties": { "payload": { "$ref": "#/definitions/payloadTypeA" } } }

Следующая проблема - как комбинировать условные выражения. Комбинируя вышеуказанное исправление с тем, что у вас есть сейчас, это будет выглядеть примерно так.

"properties": {
  "workload": { "enum": ["A","B"] }
},
"oneOf": [
  {
    "if": { "properties": { "workload": { "const": "A" } } },
    "then": { "properties": { "payload": { "$ref": "#/definitions/payloadTypeA" } } }
  },
  {
    "if": { "properties": { "workload": { "const": "B" } } },
    "then": { "properties": { "payload": { "$ref": "#/definitions/payloadTypeB" } } }
  }
]

Когда if не работает, это не приводит к нарушению схемы. Схема завершится ошибкой, только если if проходит , а then ложно. Итак, если дана действительная схема, подобная этой.

{
  "workload": "B",
  "payload": {
    "requestType": "B1",
  }
}
  • /oneOf/0 пройдёт, потому что /oneOf/0/if не пройдёт.
  • /oneOf/1 пройдёт, потому что /oneOf/1/if пройдёт и /oneOf/1/then проходит.

Поскольку обе схемы проходят, oneOf терпит неудачу. Из этого примера можно экстраполировать, что схема должна проходить только тогда, когда проходят все условия. Просто замените oneOf на allOf, и все должно работать.

"properties": {
  "workload": { "enum": ["A","B"] }
},
"allOf": [
  {
    "if": { "properties": { "workload": { "const": "A" } } },
    "then": { "properties": { "payload": { "$ref": "#/definitions/payloadTypeA" } } }
  },
  {
    "if": { "properties": { "workload": { "const": "B" } } },
    "then": { "properties": { "payload": { "$ref": "#/definitions/payloadTypeB" } } }
  }
]
...