I have the following service object in schema definitions:
"services": {
"type": "object"
"propertyNames": {
"pattern": "^[A-Za-z_]*$",
"errorMessage": "service names must be non-numeric"
}
"patternProperties": {
"^[A-Za-z_]*$": {
"type": "object"
"properties": {
"source": {
"type": ["string", "object"]
},
"port": {
"type": "number",
"errorMessage": "invalid port value"
},
"cpu": {
"type": "number",
"errorMessage": "invalid cpu value
},
"memory": {
"type": "number",
"errorMessage": "invalid memory value
},
"overrides": { "$ref": "#/definitions/overrides" },
"allOf": [...]
}
}
}
In a separate definition, I am maintaining the following override object:
"overrides": {
"type": "object",
"propertyNames": {
"pattern": "^(dev|int|trn|qa|stag|prod)?$",
"errorMessage": "override stage name must be approved environment (dev, int, trn, qa, stag, prod)"
},
"patternProperties": {
"^(dev|int|trn|qa|stag|prod)?$": {
"type": "object",
"propertyNames": {
"pattern": "^[A-Za-z_]*$",
"errorMessage": "override property name must be non-numeric"
},
"properties": {
"$ref": "..."
},
"allOf": [...]
}
}
}
For some context, this is for a configuration file where a service object is defined with port, source, cpu, mem, and other options. Each service can have an override object which can be used to replace service object properties per environment... e.g.
{
"services": {
"main": {
"source": "https://github.com/foo,
"port": 3000,
"cpu": 256,
"memory": 1,
"overrides": {
"prod": {
"port": 8443
}
}
}
}
}
My goal is to optimize this so that I do not have to maintain two of the same schemas. Essentially right now every property that exists in service definition is then duplicated as a property of the override objects. I am also maintaining separate "allOf" validations as the service object properties are required, but override object properties are all optional.
Is it possible to leverage the $ref feature in order to point to the properties of service definition from the override definition? Furthermore, would it be possible to get rid of the override schema entirely and reuse the service schema instead, or does the differences in their schema patternProperties prevent that?
I appreciate any guidance that might get me over the hump.
Full schema minus the allOf blocks for brevity:
{
"$schema": "http://json-schema.org/draft-07/schema#",
"definitions": {
"services": {
"type": "object",
"propertyNames": {
"pattern": "^[A-Za-z_]*$",
"errorMessage": "service names must be non-numeric"
},
"patternProperties": {
"^[A-Za-z_]*$": {
"type": "object",
"propertyNames": {
"pattern": "^[A-Za-z_]*$",
"errorMessage": "service property names must be non-numeric"
},
"properties": {
"source": {
"type": ["string", "object"]
},
"port": {
"type": "number",
"errorMessage": "invalid port value"
},
"cpu": {
"type": "number",
"enum": [256, 512, 1024, 2048, 4096],
"errorMessage": "invalid cpu value - should be one of the following: 256, 512, 1024, 2048, 4096"
},
"memory": {
"type": "number",
"enum": [0.5, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11,
12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
22, 23, 24, 25, 26, 27, 28, 29, 30],
"errorMessage": "memory value should be 0.5 - 30"
},
"environment": {
"type": "object",
"errorMessage": "invalid environment variables defined - must be an object"
},
"overrides": { "$ref": "#/definitions/overrides" }
},
"required": ["source", "port", "cpu", "memory", "min_instances"],
"errorMessage": {
"required": {
"source": "missing service source",
"port": "missing service port",
"cpu": "missing service cpu",
"memory": "missing service memory",
"min_instances": "missing minimum required service instances"
},
"type": "service must have at least one defined property",
"additionalProperties": "invalid property found in service definition"
},
"allOf": [...],
"additionalProperties": false
}
},
"errorMessage": { "type": "must have at least one defined service" }
},
"overrides": {
"type": "object",
"propertyNames": {
"pattern": "^(dev|int|trn|qa|stag|prod)?$",
"errorMessage": "override stage name must be approved environment (dev, int, trn, qa, stag, prod)"
},
"patternProperties": {
"^(dev|int|trn|qa|stag|prod)?$": {
"type": "object",
"propertyNames": {
"pattern": "^[A-Za-z_]*$",
"errorMessage": "override property name must be non-numeric"
},
"properties": {
"port": {
"type": "number",
"errorMessage": "invalid port value"
},
"cpu": {
"type": "number",
"enum": [256, 512, 1024, 2048, 4096],
"errorMessage": "invalid cpu value - should be one of the following: 256, 512, 1024, 2048, 4096"
},
"memory": {
"type": "number",
"enum": [0.5, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11,
12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
22, 23, 24, 25, 26, 27, 28, 29, 30],
"errorMessage": "memory value should be 0.5 - 30"
},
"environment": {
"type": "object",
"errorMessage": "invalid environment variables defined - must be an object"
}
},
"errorMessage": {
"type": "environment must have at least one defined override",
"additionalProperties": "invalid property found in override definition"
},
"allOf": [...],
"additionalProperties": false
}
},
"errorMessage": { "type": "overrides must have at least one defined environment" }
}
},
"type": "object",
"properties": {
"name": {
"type": "string",
"errorMessage": "app name should be string"
},
"account": {
"type": "string",
"errorMessage": "invalid account value"
},
"id": {
"type": "string",
"errorMessage": "invalid id tag value"
},
"services": {
"$ref": "#/definitions/services"
},
"stages": {
"type": "array",
"errorMessage": "invalid stages option - must be an array"
}
},
"required": ["name", "account", "id", "services"],
"errorMessage": {
"required": {
"name": "missing app name",
"account": "missing designated account",
"id": "missing designated id tag",
"services": "no services are defined"
}
}
}