amitchone
amitchone

Reputation: 1638

JSON Schema validating JSON with different property names

I am working with JSON Schema Draft 4 and am experiencing an issue I can't quite get my head around. Within the schema below you'll see an array, metricsGroups where any item should equal exactly oneOf the defined sub-schemas. Within the sub-schemas you'll notice that they both share the property name timestamp, but metricsGroupOne has the properties temperature and humidity whilst metricsGroupTwo has properties PIR and CO2. All properties within both metricsGroups are required.

Please see the schema below. Below the schema is an example of some data that I'd expect to be validated, but instead is deemed invalid and an explanation of my issue.

{
  "type": "object",
  "properties": {
    "uniqueId": {
      "type": "string"
    },
    "metricsGroups": {
      "type": "array",
      "minItems": 1,
      "items": {
        "oneOf": [
          {
            "type": "object",
            "properties": {
              "metricsGroupOne": {
                "type": "array",
                "minItems": 1,
                "items": {
                  "type": "object",
                  "properties": {
                    "timestamp": {
                     "type": "string",
                      "format": "date-time"
                    },
                    "temperature": {
                      "type": "number"
                    },
                    "humidity": {
                      "type": "array",
                     "items": {
                        "type": "number"
                      }
                    }
                  },
                  "additionalProperties": false,
                  "required": [
                    "timestamp",
                    "temperature",
                    "humidity"
                  ]
                }
              }
            },
            "required": [
              "metricsGroupOne"
            ]
          },
          {
            "type": "object",
            "properties": {
              "metricsGroupTwo": {
                "type": "array",
                "minItems": 1,
                "items": {
                  "type": "object",
                  "properties": {
                    "timestamp": {
                      "type": "string",
                      "format": "date-time"
                    },
                    "PIR": {
                      "type": "array",
                      "items": {
                        "type": "number"
                      }
                    },
                    "CO2": {
                      "type": "number"
                    }
                  },
                  "additionalProperties": false,
                  "required": [
                    "timestamp",
                    "PIR",
                    "CO2"
                  ]
                }
              }
            },
            "required": [
              "metricsGroupTwo"
            ]
          }
        ]
      }
    }
  },
  "additionalProperties": false,
  "required": [
    "uniqueId",
    "metricsGroups"
  ]
}

Here's some data that I believe should be valid:

{
  "uniqueId": "d3-52-f8-a1-89-ee",
  "metricsGroups": [
    {
      "metricsGroupOne": [
        {"timestamp": "2020-03-04T12:34:00Z", "temperature": 32.5, "humidity": [45.0] }
      ],
      "metricsGroupTwo": [
        {"timestamp": "2020-03-04T12:34:00Z", "PIR": [16, 20, 7], "CO2": 653.76 }
      ]
    }
  ]
}

The issue I am facing is that both of the metricsGroup arrays in my believed to be valid data validate against both of the sub-schemas - this then invalidates the data due to the use of the oneOf keyword. I don't understand how the entry for metricsGroupOne validates against the schema for metricsGroupTwo as the property names differ and vice versa.

I'm using an node library under the hood that throws this error, but I've also tested that the same error occurs on some online validation testing websites:

Any help is appreciated. Thanks, Adam

Upvotes: 1

Views: 1919

Answers (1)

Relequestual
Relequestual

Reputation: 12355

JSON Schema uses a constraints based approach. If you don't define something is not allowed, it is allowed.

What's happening here is, you haven't specificed in oneOf[1] anything which would make the first item in your instance data array invalid.

Lete me illistrate this with a simple example.

My schema. I'm going to use draft-07, but there's no difference in this principal for draft-04

{
  "oneOf": [
    {
      "properties": {
        "a": true
      }
    },
    {
      "properties": {
        "b": false
      }
    }
  ]
}

And my instance:

{
  "a": 1
}

This fails validation because the instance is valid when both oneOf schemas are applied.

Demo: https://jsonschema.dev/s/EfUc4

If the instance was in stead...

{
  "a": 1,
  "b": 1
}

This would be valid, because the instance is fails validation for the subschema oneOf[1].

If the instance was...

{
  "b": 1
}

It would be valid according to oneOf[0] but not according to oneOf[1], and therefore overall would be valid because it is only valid according to one subschema.

In your case, you probably need to use additionalProperties to make properties you haven't defined in properties dissallowed. I can't tell from your question if you want to allow both properties, because your schema is defined as oneOf which seems to conflict with the instance you expect to be valid.

Upvotes: 1

Related Questions