Reputation: 6263
I'm new to JSON schema. My goal is to have a JSON property that is an object. It's keys relate to each other, meaning multiple keys always have the same values together. This will probably help make it clear, it's my attempt to do this with an enum:
{
"$schema": "https://json-schema.org/draft/2019-09/schema",
"title": "Part",
"type": "object",
"properties": {
"relationship": {
"type": "object",
"enum": [
{
"code": "1",
"value": "MEMBER"
},
{
"code": "2",
"value": "SPOUSE"
},
{
"code": "3",
"value": "CHILD"
},
{
"code": "4",
"value": "STUDENT"
},
{
"code": "5",
"value": "DISABILITY_DEPENDENT"
},
{
"code": "6",
"value": "ADULT_DEPENDENT"
},
{
"code": "8",
"value": "DOMESTIC_PARTNER"
}
]
}
}
}
So using an enum like this works, even though I can't find it anywhere in the JSON Schema spec. However, the error message sucks. Normally I get the most extremely detailed error messages from schema validation, however in this case I do not.
$.part.relationship: does not have a value in the enumeration [, , , , , , ]
I'm not sure what I'm doing wrong. I'm using a Java parser for JSON Schema:
<dependency>
<groupId>com.networknt</groupId>
<artifactId>json-schema-validator</artifactId>
<version>1.0.53</version>
</dependency>
Not sure if the error message is the fault of the parser or something I'm doing bad with the schema.
Upvotes: 1
Views: 11014
Reputation: 455
I think what you're actually looking for is the "anyOf" keyword, where you can create a union of constant objects for a property.
Something like this:
{
"$schema": "https://json-schema.org/draft/2019-09/schema",
"title": "Part",
"type": "object",
"properties": {
"relationship": {
"type": "object",
"anyOf": [
{
"properties": {
"code": { "const": "1" },
"value": { "const": "MEMBER" }
},
"additionalProperties": false
},
{
"properties": {
"code": { "const": "2" },
"value": { "const": "SPOUSE" }
},
"additionalProperties": false
},
{
"properties": {
"code": { "const": "3" },
"value": { "const": "CHILD" }
},
"additionalProperties": false
},
{
"properties": {
"code": { "const": "4" },
"value": { "const": "STUDENT" }
},
"additionalProperties": false
},
{
"properties": {
"code": { "const": "5" },
"value": { "const": "DISABILITY_DEPENDENT" }
},
"additionalProperties": false
},
{
"properties": {
"code": { "const": "6" },
"value": { "const": "ADULT_DEPENDENT" }
},
"additionalProperties": false
},
{
"properties": {
"code": { "const": "8" },
"value": { "const": "DOMESTIC_PARTNER" }
},
"additionalProperties": false
}
]
}
},
"required": ["relationship"]
}
Upvotes: 1
Reputation: 8428
If code
and value
always have the same values relative to each other, why encode both in the JSON? Just encode a single value in the JSON and infer the other in the application.
This will be much easier to validate.
Upvotes: 0
Reputation: 44150
It was news to me, but according to the spec it does seem that objects are valid enum values. That said, your usage is quite unusual. I've not seen it used before.
the six primitive types ("null", "boolean", "object", "array", "number", or "string") ...
6.1.2. enum ...
Elements in the array might be of any type, including null.
Your problem is fundamentally that the library that you're using doesn't know how to convert those objects to printable strings. Even if it did give it a reasonable go, you might end up with
does not have a value in the enumeration [{"code": "1", "value":"MEMBER"}, {"code": "2" ...
which might be okay, but it's hardly amazing. If the code and value were both valid but didn't match, you might have to look quite closely at the list before you ever saw the problem.
JSON Schema in general is not very good at enforcing constraints between what it considers to be 2 unrelated fields. That's beyond the scope of it what it aims to do. It's trying to validate the structure. Dependencies between fields are business constraints, not structural ones.
I think the best thing you could do to achieve readable error messages would be to have 2 sub-properties, each with an enumeration containing 8 values; one for the codes, one for the values.
Then you'll get
$.part.relationship.code does not have a value in the enumeration [1,2,3,4 ...
or
$.part.relationship.value does not have a value in the enumeration ["MEMBER", "SPOUSE", ...
You can do some additional business validation on top of the schema validation if enforcing that constraint is important to you. Then generate your own error such as
code "1" does not match value "SPOUSE"
Upvotes: 4