skip to Main Content

I like to write a JSON schema validation for this kind of yml

stages:

  - template: template-a.yml
    parameters:
      a-param1: abc
      a-param2: xy

  - template: template-b.yml
    parameters:
      b-param1: df
      b-param2: yz

So depending of the value of property "template", the property object "parameters" should have different properties.

I tried something like this, but if/then is not working for the object properties.
(if the property is on same level like "template" it’s working)

{
    "$schema": "http://json-schema.org/draft-07/schema#",
    "$ref": "#/definitions/azure-templates",
    "definitions": {
        "azure-templates": {
            "type": "object",
            "additionalProperties": false,
            "properties": {
                "stages": {
                    "type": "array",
                    "items": {
                        "anyOf": [
                            {
                                "$ref": "#/definitions/template-select"
                            }
                        ]
                    }
                }
            },
            "required": [
                "stages"
            ],
            "title": "azure-pipeline"
        },
        "template-params-a": {
            "if": {
                "properties": {
                    "template": {
                        "const": "template-a.yml"
                    }
                },
                "required": [
                    "template"
                ]
            },
            "then": {
                "properties": {
                    "parameters": {
                        "type": "object",
                        "additionalProperties": false,
                        "properties": {
                            "a-param1": {
                                "type": "string"
                            },
                            "a-param2": {
                                "type": "string"
                            }
                        }
                    }
                }
            }
        },
        "template-params-b": {
            "if": {
                "properties": {
                    "template": {
                        "const": "template-b.yml"
                    }
                },
                "required": [
                    "template"
                ]
            },
            "then": {
                "properties": {
                    "parameters": {
                        "type": "object",
                        "additionalProperties": false,
                        "properties": {
                            "b-param1": {
                                "type": "string"
                            },
                            "b-param2": {
                                "type": "string"
                            }
                        }
                    }
                }
            }
        },
        "template-select": {
            "type": "object",
            "additionalProperties": false,
            "properties": {
                "template": {
                    "enum": [
                        "template-a.yml",
                        "template-b.yml"
                    ]
                }
            },
            "allOf": [
                {
                    "$ref": "#/definitions/template-params-a",
                    "$ref": "#/definitions/template-params-b"
                }
            ],
            "required": [
                "template"
            ],
            "title": "Template"
        }
    }
}

2

Answers


    • the root $ref should be wrapped in an allOf. This behavior was later updated in Draft 2019-09 which allowed a root $ref and definitions(or any other keyword as a sibling) to be validated
    • the additionalProperties:false in your template-select schema is preventing the parameters from being used because in draft-07, allOf and additionalProperties:false don’t play nicely together without some gymnastics in the schema. (if you really want to enforce this constraint, I’ve updated the schema)
    • I removed the anyOf in the items schema, it’s not necessary with a single schema ref.
    {
        "$schema": "http://json-schema.org/draft-07/schema#",
        "allOf": [
            {
                "$ref": "#/definitions/azure-templates"
            }
        ],
        "definitions": {
            "azure-templates": {
                "type": "object",
                "additionalProperties": false,
                "properties": {
                    "stages": {
                        "type": "array",
                        "items": {
                            "$ref": "#/definitions/template-select"
                        }
                    }
                },
                "required": [
                    "stages"
                ],
                "title": "azure-pipeline"
            },
            "template-params-a": {
                "if": {
                    "properties": {
                        "template": {
                            "const": "template-a.yml"
                        }
                    },
                    "required": [
                        "template"
                    ]
                },
                "then": {
                    "properties": {
                        "parameters": {
                            "type": "object",
                            "additionalProperties": false,
                            "properties": {
                                "a-param1": {
                                    "type": "string"
                                },
                                "a-param2": {
                                    "type": "string"
                                }
                            }
                        }
                    }
                }
            },
            "template-params-b": {
                "if": {
                    "properties": {
                        "template": {
                            "const": "template-b.yml"
                        }
                    },
                    "required": [
                        "template"
                    ]
                },
                "then": {
                    "properties": {
                        "parameters": {
                            "type": "object",
                            "additionalProperties": false,
                            "properties": {
                                "b-param1": {
                                    "type": "string"
                                },
                                "b-param2": {
                                    "type": "string"
                                }
                            }
                        }
                    }
                }
            },
            "template-select": {
                "type": "object",
                "additionalProperties": false,
                "properties": {
                    "template": {
                        "enum": [
                            "template-a.yml",
                            "template-b.yml"
                        ]
                    }, 
                    "parameters": true
                },
                "allOf": [
                    {"$ref": "#/definitions/template-params-a"},
                    {"$ref": "#/definitions/template-params-b"}
                ],
                "required": [
                    "template", "parameters"
                ],
                "title": "Template"
            }
        }
    }
    
    Login or Signup to reply.
  1. Using VSC, it seems to suggest the properties correctly, based on the conditional validation defined.

    VSC sample

    VSC sample

    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search