简体   繁体   中英

How to use oneOf alongside a common sub-schema (V4)

I'm having trouble trying to create a schema that makes use of both oneOf and a common referenced sub-schema, in order to avoid having to duplicate parts of the schema. The JSON that the schema should be validating against looks as follows:

{
  "createdDate": "2015-01-20T17:10:05Z",
  "createdBy": "testUser",
  "lastModifiedDate": "2015-01-20T17:10:05Z",
  "lastModifiedBy": "testUser",
  "fileUrl": {
    "path": "/path/to/file",
    "fileName": "file.pdf"
  },
  "referenceType": "person",
  "fileType": "certificate",
  "personId": "12345"
}

From this, the common part is:

{
  "createdDate": "2015-01-20T17:10:05Z",
  "createdBy": "testUser",
  "lastModifiedDate": "2015-01-20T17:10:05Z",
  "lastModifiedBy": "testUser",
  "fileUrl": {
    "path": "/path/to/file",
    "fileName": "file.pdf"
  }
}

The remaining 3 fields are always the same in name and all required, but the allowed enum values for them will vary.

So the schema for the remaining 3 could be one of the following:

{
"properties": {
    "referenceType": {
        "type": "string",
        "enum": [
            "vehicle"
        ]
    },
    "fileType": {
        "type": "string",
        "enum": [
            "registration document"
        ]
    },
    "vehicleId": {
        "type": "string",
        "pattern": "[^ ]"
    }
},
"required": [
    "vehicleId"
]
}

OR

{
    "properties": {
        "referenceType": {
            "type": "string",
            "enum": [
                "person"
            ]
        },
        "fileType": {
            "type": "string",
            "enum": [
                "certificate"
            ]
        },
        "personId": {
            "type": "string",
            "pattern": "[^ ]"
        }
    },
    "required": [
        "personId"
    ]
}

I can't seem to create a schema whereby I can avoid duplicating the common fields, and have the oneOf, and set additionalProperties to false across the whole schema. With the below example, trying to set additionalProperties to false causes validation errors. Is it possible to do what I'm trying to do?

{
    "type": "object",
    "$schema": "http://json-schema.org/draft-04/schema#",
    "definitions": {
        "commonFile": {
            "properties": {
                "createdDate": {
                    "type": "string",
                    "format": "date-time"
                },
                "createdBy": {
                    "type": "string",
                    "pattern": "[^ ]"
                },
                "lastModifiedDate": {
                    "type": "string",
                    "format": "date-time"
                },
                "lastModifiedBy": {
                    "type": "string",
                    "pattern": "[^ ]"
                },
                "fileUrl": {
                    "type": "object",
                    "additionalProperties": false,
                    "properties": {
                        "path": {
                            "type": "string",
                            "pattern": "[^ ]"
                        },
                        "fileName": {
                            "type": "string",
                            "pattern": "[^ ]"
                        }
                    },
                    "required": [
                        "path",
                        "fileName"
                    ]
                }
            }   
        }
    },
    "oneOf": [{
            "allOf": [
                {"$ref": "#/definitions/commonFile"}, 
                {
                    "properties": {
                        "referenceType": {
                            "type": "string",
                            "enum": [
                                "person"
                            ]
                        },
                        "fileType": {
                            "type": "string",
                            "enum": [
                                "certificate"
                            ]
                        },
                        "personId": {
                            "type": "string",
                            "pattern": "[^ ]"
                        }
                    },
                    "required": [
                        "personId"
                    ]
                }
            ]
        }, {
            "allOf": [
                {"$ref": "#/definitions/commonFile"}, 
                {
                    "properties": {
                        "referenceType": {
                            "type": "string",
                            "enum": [
                                "vehicle"
                            ]
                        },
                        "fileType": {
                            "type": "string",
                            "enum": [
                                "registration document"
                            ]
                        },
                        "vehicleId": {
                            "type": "string",
                            "pattern": "[^ ]"
                        }
                    },
                    "required": [
                        "vehicleId"
                    ]
                }
            ]
        }
    ],
    "required": [
        "createdDate",
        "createdBy",
        "lastModifiedDate",
        "lastModifiedBy",
        "fileUrl",
        "referenceType",
        "fileType"
    ]
}

I recommend not setting additionalProperties to false . It is usually best just to quietly ignore properties that are not defined. The following schema is what you would have to do to accomplish your goal.

{
  "$schema": "http://json-schema.org/draft-04/schema#",
  "type": "object",
  "properties": {
    "createdDate": { "type": "string", "format": "date-time" },
    "createdBy": { "type": "string", "pattern": "[^ ]" },
    "lastModifiedDate": { "type": "string", "format": "date-time" },
    "lastModifiedBy": { "type": "string", "pattern": "[^ ]" },
    "fileUrl": {
      "type": "object",
      "additionalProperties": false,
      "properties": {
        "path": { "type": "string", "pattern": "[^ ]" },
        "fileName": { "type": "string", "pattern": "[^ ]" }
      },
      "required": ["path", "fileName"]
    },
    "referenceType": { "type": "string" },
    "fileType": { "type": "string" },
    "personId": {},
    "vehicleId": {}
  },
  "additionalProperties": false,
  "anyOf": [
    {
      "properties": {
        "referenceType": { "enum": ["person"] },
        "fileType": { "enum": ["certificate"] },
        "personId": { "type": "string", "pattern": "[^ ]" }
      },
      "required": ["personId"],
      "not" : { "required": ["vehicleId"] }
    },
    {
      "properties": {
        "referenceType": { "enum": ["vehicle"] },
        "fileType": { "enum": ["registration document"] },
        "vehicleId": { "type": "string", "pattern": "[^ ]" }
      },
      "required": ["vehicleId"],
      "not" : { "required": ["personId"] }
    }
  ],
  "required": ["createdDate", "createdBy", "lastModifiedDate", "lastModifiedBy", "fileUrl", "referenceType", "fileType"]
}

The first thing I did was remove all the extraneous allOf s. Only one anyOf is needed. I defined the common properties in the main schema. The variations are described in the anyOf clause.

If you set additionalProperties to false , an additional schema (such as allOf , oneOf , and anyOf ) can not introduce new properties. This means that all properties that are going to be allowed in this schema must be included in the schema that declares additionalProperties to be false . That is why I declared referenceType , fileType , personId , and vechicleId in the main schema.

The problem now is that additionalProperties no longer excludes vehicleId when referenceType is person or personId when referenceType is vehicle . To make sure this isn't allowed, I added the not clauses.

If were you add a third variation, restricting additional properties gets even more difficult. It's not just adding an additional referenceType to the anyof schema array. You also have to add new properties to the main schema and disallow those new types for all of the existing referenceTypes . You have to make changes all over the schema instead of just the area that is changing. This is why setting additionalProperties to false is generally not the best idea.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM