Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

JSON schema: Why does "constant" not validate the same way as a single-valued "enum"?

I have an object that provides a sort of audit log of versions of an asset. A couple of its properties (versionSource.metadata and versionSource.files) are objects that should validate against one of two schemas, depending on the value of one of their properties. I started off using a constant in my sub-schemas (inside the oneOf, but that was saying that all the the sub-schemas validated (thus breaking the oneOf since more than one validated. Changing it to a single-valued enum worked, though.

Why the difference in validation?

Here's the original schema:

{
   "$id": "https://example.com/schemas/asset-version.json",
   "title": "Audit log of asset versions",
   "$schema": "http://json-schema.org/draft-07/schema",

   "type": "object",
   "required": [
      "assetID",
      "version",
      "versionSource"
   ],

   "properties": {
      "assetID": {
         "type": "string"
      },
      "version": {
         "type": "integer",
         "minimum": 1
      },
      "versionSource": {
         "type": "object",
         "properties": {
            "metadata": {
               "type": "object",
               "oneOf": [
                  {
                     "properties": {
                        "sourceType": { "constant": "client" }
                     }
                  },
                  {
                     "$ref": "#/definitions/version-source-previous-version"
                  }
               ]
            },
            "files": {
               "type": "object",
               "oneOf": [
                  {
                     "properties": {
                        "sourceType": { "constant": "upload" },
                        "sourceID": {
                           "type": "string"
                        }
                     }
                  },
                  {
                     "$ref": "#/definitions/version-source-previous-version"
                  }
               ]
            }
         }
      }
   },

   "definitions": {
      "version-source-previous-version": {
         "properties": {
            "sourceType": { "constant": "previous-version" },
            "sourceID": {
               "type": "integer",
               "minimum": 1
            }
         }
      }
   }
}

Here's one example document:

{
   "assetID": "0150a186-068d-43e7-bb8b-0a389b572379",
   "version": 1,
   "versionSource": {
      "metadata": {
         "sourceType": "client"
      },
      "files": {
         "sourceType": "upload",
         "sourceID": "54ae67b0-3e42-464a-a93f-3143b0f078fc"
      }
   },
   "created": "2018-09-01T00:00:00.00Z",
   "lastModified": "2018-09-02T12:10:00.00Z",
   "deleted": "2018-09-02T12:10:00.00Z"
}

And one more:

{
   "assetID": "0150a186-068d-43e7-bb8b-0a389b572379",
   "version": 2,
   "versionSource": {
      "metadata": {
         "sourceType": "previous-version",
         "sourceID": 1
      },
      "files": {
         "sourceType": "previous-version",
         "sourceID": 1
      }
   },
   "created": "2018-09-01T00:00:00.00Z",
   "lastModified": "2018-09-02T12:10:00.00Z",
   "deleted": "2018-09-02T12:10:00.00Z"
}

Here's the error I get:

Message: JSON is valid against more than one schema from 'oneOf'. Valid schema indexes: 0, 1. Schema path: https://example.com/schemas/asset-version.json#/properties/versionSource/properties/metadata/oneOf

Since sourceType is a constant in both schemas inside the oneOf, I'm really not sure how my object could possibly be valid against both schemas.

Changing the schema to the following, though, worked:

{
   "$id": "https://example.com/schemas/asset-version.json",
   "title": "Audit log of asset versions",
   "$schema": "http://json-schema.org/draft-07/schema",

   "type": "object",
   "required": [
      "assetID",
      "version",
      "versionSource"
   ],

   "properties": {
      "assetID": {
         "type": "string"
      },
      "version": {
         "type": "integer",
         "minimum": 1
      },
      "versionSource": {
         "type": "object",
         "properties": {
            "metadata": {
               "type": "object",
               "oneOf": [
                  {
                     "properties": {
                        "sourceType": { "enum": [ "client" ] }
                     }
                  },
                  {
                     "$ref": "#/definitions/version-source-previous-version"
                  }
               ]
            },
            "files": {
               "type": "object",
               "oneOf": [
                  {
                     "properties": {
                        "sourceType": { "enum": [ "upload" ] },
                        "sourceID": {
                           "type": "string"
                        }
                     }
                  },
                  {
                     "$ref": "#/definitions/version-source-previous-version"
                  }
               ]
            }
         }
      }
   },

   "definitions": {
      "version-source-previous-version": {
         "properties": {
            "sourceType": { "enum": [ "previous-version" ] },
            "sourceID": {
               "type": "integer",
               "minimum": 1
            }
         }
      }
   }
}

What am I missing?

like image 560
Jeremy Thomerson Avatar asked Jan 22 '18 20:01

Jeremy Thomerson


1 Answers

It was my own typo ... constant should have been const. :facepalm:

like image 91
Jeremy Thomerson Avatar answered Sep 18 '22 01:09

Jeremy Thomerson