Attribut jsonSchema requis sous condition

97

Dans jsonSchema, vous pouvez indiquer si les champs définis sont obligatoires ou non en utilisant l' requiredattribut:

{
    "$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 souhaite que le messageVersionchamp ne soit pas obligatoire. Existe-t-il un moyen de rendre le caractère obligatoire de ce champ conditionnel?

Tom Redfern
la source
Oui, cela devrait être possible. Quelles informations contenues dans les données déclencheraient l'obligation?
jruizaranguren
@SarveswaranMeenakshiSundaram - Je ne sais pas que j'ai seulement utilisé la v4 du schéma json
tom redfern
Est-ce possible du tout dans la version 3?
Sarvesh
@SarveswaranMeenakshiSundaram - Je ne sais pas. Essayez-le et faites-le nous savoir s'il vous plaît!
tom redfern

Réponses:

264

Selon votre situation, il existe plusieurs approches différentes. Je peux penser à quatre façons différentes d'exiger conditionnellement un champ.

Dépendances

Le dependenciesmot-clé est une variante conditionnelle du requiredmot - clé. 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 courte si le schéma ne contient que le requiredmot - clé.

{
  "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 que si A est vrai, alors B doit également être vrai. L'implication peut également être exprimée par "! 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", alors 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", les #/anyOf/0correspondances et la validation réussissent. Si "foo" est égal à "bar", #/anyOf/0échoue et #/anyOf/1doit être valide pour que la anyOfvalidation 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 récent au schéma JSON (draft-07) ajoute les mots - clés if, thenet else. Si la propriété "foo" est égale à "bar", alors 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 Implication mise à jour et section If-Then-Else ajoutée.

EDIT 06/04/2018: Correction de bug pour If-Then-Else et mise à jour des singleton enumà utiliser const.

Jason Desrosiers
la source
7
@scubbo Je ne suis pas fan des if-then-elsemots - clés et je refuse de les utiliser. Mais, si vous choisissez de l'utiliser, je suggère de toujours les envelopper dans un allOfqui ne contient que ces trois mots-clés. { ...other_keywords..., "allOf": [{ "if": ..., "then": ..., "else": ... }], ...more_keywords... }
Jason Desrosiers
2
@Jason Pourquoi pas fan de if...? Je pense qu'une brève opinion à ce sujet dans votre réponse serait tout à fait justifiée. Ou est-ce une longue histoire?
Clay Bridges
6
@ClayBridges La section des commentaires n'est pas le bon endroit pour cette discussion, mais voici la version courte. En règle générale, les mots clés du schéma JSON sont sans état. Aucune information autre que la valeur du mot clé ne peut être utilisée pour valider l'instance. if, thenet elseenfreignent cette règle car ils dépendent les uns des autres.
Jason Desrosiers
3
@GGirard, c'est le meilleur traitement de l'utilisation de ces modèles dans le schéma JSON que je connaisse. Les opérations booléennes sont officiellement documentées mais le reste n'est que mathématique. allOf== AND, anyOf== OR, oneOf== XOR et not== NOT. Vous pouvez google "algèbre booléenne" pour plus de ressources sur les choses mathématiques (comme l'implication).
Jason Desrosiers
2
@AlexeyShrub Je voulais écrire à ce sujet depuis un moment, mais j'ai été distrait par d'autres choses. Je suis fan de l' idée d'un conditionnel. Cela permet aux gens de mieux comprendre. Mon objection concerne la façon dont il a été défini comme trois mots-clés avec état distincts (voir le commentaire précédent). Le fait d'avoir des mots-clés qui enfreignent les propriétés architecturales suivies par d'autres mots-clés rend les validateurs de schéma JSON plus difficiles à implémenter et moins efficaces. Si les conditions étaient définies d'une manière différente qui était apatride, alors je n'aurais aucune objection.
Jason Desrosiers