i am trying to use a schema to validate some input data in an ionic WebApp. But it doesnt seem to work the way i want it to. Schema and example input data here: https://www.jsonschemavalidator.net/s/ukPB5SkA.
specifically the object should be allowed to contain properties “header” “footer” “color” and “typeface”. Yet other properties seem to be allowed despite additionalProperties being set to false.
I also tired adding:
"patternProperties": {
".*": "string"
}
i use ajv in my project so i tried using a format:
import addFormats from 'ajv-formats';
import Ajv2019 from "ajv/dist/2019"
const ajv = new Ajv2019({strict: true, removeAdditional: 'all', allowUnionTypes: true, passContext: true})
addFormats(ajv)
ajv.addFormat("collection", {
type: "string",
validate: (x) => Object.keys(Properties).includes(x)
})
enum Properties {
'header',
'footer',
'color',
'typeface'
}
const complexSchemaFormat = {
"type": "object",
"properties": {
"propertyNames": {
"type": "string",
"format": "collection"
},
"additionalProperties": false
}
} as const
const complexInput2 = {
"jiii": 2,
"juuu": "laal"
}
protected doThing() {
const complexIsValid3 = ajv.validate(complexSchemaFormat,complexInput2)
console.log(complexIsValid3) // is true, should be false
}
Alternative from the previous answer
{
"$schema": "https://json-schema.org/draft/2019-09/schema",
"additionalProperties": false,
"type": "object",
"properties": {
"header": {"type": "string"},
"footer": {"type": "string"},
"color": {"type": "string"},
"typeface": {"type": "string"}
}
}
propertyNames
is an applicator similar to properties
.
The description of this keyword states:
The propertyNames keyword in is used to define constraints on the property names within an object instance. It allows you to specify a schema that all the property names in an object instance must adhere to.
The way you have written your schema, the actual property name defined is propertyNames
.
{
"propertyNames": "something"
}
It should be something like this where you want to constraint the naming to your enum. BUT, this doesn’t give you way to constraint the values of those properties.
{
"$schema": "https://json-schema.org/draft/2019-09/schema",
"propertyNames": {
"pattern": "header|footer|color|typeface"
}
}
You probably really want to do something like this where you don’t even need to define a custom format
. JSON Schema validation will validate what you are trying to do with the custom format with the following
{
"$schema": "https://json-schema.org/draft/2019-09/schema",
"unevaluatedProperties": false,
"patternProperties": {
"header|footer|color|typeface": {
"type": "string"
}
}
}
This basically says, any property defined in this schema must be one of the values in patternProperties
and then it must validate as a string
3
I found a suitable solution. I put the enums into separate schemas and then used these subschemas to
- have only the propertyNames allowed that are keys of an ts enum
- have an array property “flags” allowed that can only have the listed properties as members.
This makes the schema much longer and kind of convoluted but it does what i want it to do:
export const PropertiesSchema = {
"$schema": "http://json-schema.org/draft-07/schema#",
"$ref": "#/definitions/Properties",
"definitions": {
"Properties": {
"type": "object",
"properties": {
"flags": {
"type": "array",
"items": {
"$ref": "#/definitions/Flags"
}
}
},
"propertyNames": {
"$ref": "#/definitions/StyleParams"
},
},
"StyleParams": {
"type": "string",
"enum": [
"flags",
...Object.keys(properties) // ts enum
]
},
"Flags": {
"type": "string",
"enum": [
classconstants.Constant1,
classconstants.Constant2,
classconstants.Constant3
]
}
}
} as const