0

Need help to find the bug with this schema. It has oneOf operator. Schema is here :

   `{
    "type": "object",
    "required": [
        "type",
        "body"
    ],
    "properties": {
        "type": {
            "description": "type of the document to post",
            "type": "string",
            "enum": [
                "123",
                "456"                    
            ]
        },
        "body": {
            "type": "object",
            "description": "body",
            "oneOf": [{
                "$ref": "#/definitions/abc",
                "$ref": "#/definitions/def"
            }]
        }
    },
    "definitions": {
        "abc": {                
            "type": "array",
            "description": "abc",
           "properties" : {
               "name" : { "type" : "string"  }
         }
        },
        "def": {                
            "type": "array",
            "description": "users","properties" : {
               "name" : { "type" : "string"  }
         }
        }
    }
}`

My Json is this :

  `{
            "type": "123",
            "body": {
                "abc": [{
                    "name": "test"
                }]
            }
        }`

It does not validate with tv4 and I also tried this online tool. It works without oneOf operator. Otherwise it does not validate it any tool.

Edit :

After reading the answers I modified the schema. New schema is :

{
"type": "object",
"properties": {
    "type": {
        "description": "type of the document to post",
        "type": "string",

    },
    "body": {
        "type": "object",
        "description": "body",
        "properties": {
            "customers": {
                "type": "array"
            }
        },
        "anyOf": [
            {
                "title": "customers prop",
                "properties": { 
                    "customers": {
                        "type": "array",
                        "description": "customers",
                        "items": {
                            "type": "object",
                            "properties": {
                                "name": {
                                    "type": "string"
                                }
                            }
                        }
                    }
                }
            }
        ]
    }
  }
}

And json is here

{
"type": "customer",
"body": {
    "none": [
        {
            "name": "test"
        }
    ]
  }
}

But it validates. I want to enforce one of "customers" or "users" in the body. To test I have removed users from the body.

Pl help.

Bhoomi
  • 781
  • 6
  • 22

3 Answers3

3

The issue is that the data is passing both of your sub-schemas. oneOf means "match exactly one" - if you want "match at least one", then use anyOf.

In fact, both of your sub-schemas will pass all data. The reason is that properties is ignored when dealing with arrays.

What you presumably wanted to do instead is specify properties for the items in the array. For this, you need the items keyword:

"definitions": {
    "abc": {                
        "type": "array",
        "items": {
            "type": "object",
            "properties" : {
                "name" : { "type" : "string"  }
            }
        }
    }
}

(You'll also need to add some distinct constraints - at the moment, both the "abc" and "def" definitions are identical apart from description, which makes the oneOf impossible because it will always match both or neither.)

cloudfeet
  • 12,156
  • 1
  • 56
  • 57
2

Since you have the type at root level, you probably want the oneOf statement to check that an object with type "customer" has customers in the body (even though I would suggest skipping the body and placing customers and users directly in root object).

This works with your example, will require that an object with type "customer" has a body with "customers", and to clarify the matching, I let customer have the property "name" while the user has "username":

{
  "type": "object",
  "properties": {
    "type": { "type": "string" },
    "body": {
      "type": "object",
      "properties": {
        "customers": { 
          "type": "array",
          "items": { "$ref": "#/definitions/customer" }
        },
        "users": {
          "type": "array",
          "items": { "$ref": "#/definitions/user" }
        }
      }
    }
  },
  "definitions": {
    "customer": {
      "type": "object",
      "properties": { "name": { "type": "string" } },
      "required": [ "name" ]
    },
    "user": {
      "type": "object",
      "properties": { "username": { "type": "string" } },
      "required": [ "username" ]
    }
  },
  "oneOf": [
    {
      "properties": {
        "type": {
          "pattern": "customer"
        },
        "body": {
          "required": [ "customers" ]
        }
      }
    },
    {
      "properties": {
        "type": {
          "pattern": "user"
        },
        "body": {
          "required": [ "users" ]
        }
      }
    }
  ]
}
fiddur
  • 1,768
  • 15
  • 11
1

When using "type": "array" then the item type is defined in the "items" property not "properties" property... Also both types in oneOf are same, but only one must match.

Try

      ...
      "definitions": {
        "abc": {                
            "type": "array",
            "description": "abc",
           "items" : {
               "name" : { "type" : "string"  }
         }
        },
        "def": {                
            "type": "array",
            "description": "users",
            "items" : {
               "username" : { "type" : "string"  }
            }
        }
    }
Rico Suter
  • 11,548
  • 6
  • 67
  • 93