web-dev-qa-db-fra.com

Attribut jsonSchema requis de manière conditionnelle

Dans jsonSchema, vous pouvez indiquer si les champs définis sont obligatoires ou n'utilisent pas l'attribut "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"
    ]
}

Dans certains cas, je souhaiterais que le champ messageVersion ne soit pas obligatoire. Existe-t-il un moyen de rendre obligatoire l’obligation de ce champ?

74
tom redfern

Selon votre situation, il existe plusieurs approches différentes. Je peux penser à quatre manières différentes d'exiger un champ de manière conditionnelle.

Les dépendances

Le mot clé dependencies est une variante conditionnelle du mot clé required. Pour la propriété Foreach dans dependencies, si la propriété est présente dans le JSON en cours de validation, le schéma associé à cette clé doit également être valide. Si la propriété "foo" est présente, alors la propriété "bar" est requise

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

Il existe également une forme abrégée si le schéma ne contient que le mot clé required.

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

Implication

Si votre condition dépend de la valeur d'un champ, vous pouvez utiliser un concept logique booléen appelé implication. "A implique B" signifie effectivement, si A est vrai, alors B doit également être vrai. L'implication peut également être exprimée sous la forme "! A ou B". Soit la propriété "foo" n'est pas égale à "bar", soit la propriété "bar" est requise . Ou, en d'autres termes: Si la propriété "foo" est égale à "bar", la propriété "bar" est requise

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

Si "foo" n'est pas égal à "bar", #/anyOf/0 correspond et la validation réussit. Si "foo" est égal à "bar", #/anyOf/0 échoue et #/anyOf/1 doit être valide pour que la validation anyOf réussisse.

Enum

Si votre conditionnel est basé sur une énumération, c'est un peu plus simple. "foo" peut être "bar" ou "baz". Si "foo" est égal à "bar", alors "bar" est requis. Si "foo" est égal à "baz", alors "baz" est requis.

{
  "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"]
    }
  ]
}

Si-Alors-Sinon

Un ajout relativement nouveau à JSON Schema (draft-07) ajoute les mots-clés if, then et else. Si la propriété "foo" est égale à "bar", la propriété "bar" est requise

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

EDIT 12/23/2017: section d'implication mise à jour et ajout de la section If-Then-Else.

EDIT 06/04/2018: Correction de bogues pour If-Then-Else et mise à jour du singleton enums pour utiliser const.

192
Jason Desrosiers