Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Unexpected errors for anyOf schemas with additionalProperties: false #127

Closed
thetumper opened this issue Nov 15, 2019 · 6 comments
Closed

Comments

@thetumper
Copy link

The following is a portion of my openapi 3.0 spec, just the relevant schemas:


components:
  requestBodies:
    Contacts:
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/Contacts'
      description: Set of contact data for a new contact.
      required: true
  schemas:
    AddressArrayType:
      type: object
      properties:
        addresses:
          type: array
          items:
            $ref: '#/components/schemas/AddressType'
          minItems: 1
          maxItems: 99
      additionalProperties: false
      required:
        - addresses
    AddressType:
      type: object
      properties:
        line1:
          type: string
          description: Address line 1
          example: '300 E Main St'
        line2:
          type: string
          description: Address line 2
          example: 'Apt. 14'
        city:
          type: string
          description: City, e.g. 'Madison'
        stateCode:
          type: string
          description: State code
          example: 'WI'
          pattern: '^([A-Z]{2})$'
        zip5:
          type: string
          description: 5-digit ZIP code
          example: '53780'
          pattern: '^([0-9]{5})$'
      additionalProperties: false
      required:
        - line1
        - city
        - stateCode
        - zip5
    ContactMechanisms:
      type: object
      anyOf:
        - $ref: '#/components/schemas/AddressArrayType'
        - $ref: '#/components/schemas/EmailArrayType'
        - $ref: '#/components/schemas/PhoneArrayType'
    EmailArrayType:
      type: object
      properties:
        emails:
          type: array
          items:
            $ref: '#/components/schemas/EmailType'
          minItems: 1
          maxItems: 99
      additionalProperties: false
      required:
        - emails
    EmailType:
      type: object
      properties:
        address:
          type: string
          description: Email address
          format: email
        type:
          type: string
          enum: ['HOME', 'WORK']
      additionalProperties: false
      required:
        - address
    Contacts:
      type: object
      properties:
        contactMechanisms:
          $ref: '#/components/schemas/ContactMechanisms'
        name:
          $ref: '#/components/schemas/Name'
      additionalProperties: false
      required:
        - contactMechanisms
        - name
    Name:
      type: object
      properties:
        first:
          type: string
          description: First name, e.g. 'John'
        last:
          type: string
          description: Last name, e.g. 'Smith'
        middle:
          type: string
          description: Middle name or initial
      additionalProperties: false
      required:
        - first
        - last
    ContactsResponse:
      type: object
      properties:
        contactId:
          description: 'The Contact ID'
          type: string
          format: uuid
      additionalProperties: false
    PhoneArrayType:
      type: object
      properties:
        phones:
          type: array
          items:
            $ref: '#/components/schemas/PhoneType'
          minItems: 1
          maxItems: 99
      additionalProperties: false
      required:
        - phones
    PhoneType:
      type: object
      properties:
        number:
          type: string
          description: Phone number
        phoneType:
          type: string
          enum: ['HOME', 'WORK', 'CELL']
      additionalProperties: false
      required:
        - number

The contactMechanisms element should be allowed to have more than one of the "sub-schemas" represented, but the additionalProperties: false on each sub-schema seems to be "seen" across the contactMechanisms element, instead of being isolated to the sub-schema it is defined on.

This payload should be valid, with no errors:


{
	"contactMechanisms": {
		"addresses": [
			{
				"line1": "300 E Main St",
				"city": "Madison",
				"stateCode": "WI",
				"zip5": "53780"
			}
		],
		"emails": [
			{
				"address": "[email protected]"
			}
		]
	},
	"name": {"first": "Henry", "last": "Smith", "middle": "J" },
}

Instead, express-openapi-validator returns these errors:


[
        {
            "path": ".body.contactMechanisms.emails",
            "message": "should NOT have additional properties",
            "errorCode": "additionalProperties.openapi.validation"
        },
        {
            "path": ".body.contactMechanisms.addresses",
            "message": "should NOT have additional properties",
            "errorCode": "additionalProperties.openapi.validation"
        },
        {
            "path": ".body.contactMechanisms.addresses",
            "message": "should NOT have additional properties",
            "errorCode": "additionalProperties.openapi.validation"
        },
        {
            "path": ".body.contactMechanisms.emails",
            "message": "should NOT have additional properties",
            "errorCode": "additionalProperties.openapi.validation"
        },
        {
            "path": ".body.contactMechanisms.phones",
            "message": "should have required property 'phones'",
            "errorCode": "required.openapi.validation"
        },
        {
            "path": ".body.contactMechanisms",
            "message": "should match some schema in anyOf",
            "errorCode": "anyOf.openapi.validation"
        }
]

Ajv correctly validates this, returning no errors.

@cdimascio
Copy link
Owner

cdimascio commented Nov 15, 2019

Thanks @thetumper. Could you send me a snippet of the Ajv code that you used to compare validation; I'm particularly interested in those options.

@thetumper
Copy link
Author

Crud! I'm sorry. I realized the test case with Ajv was missing the scenario of having two contact mechanism types in the payload. It fails for Ajv also. Tests with Ajv here:

https://github.com/thetumper/contact-schema-validator

Looks like this is related to the known issue of combining schemas and restricting additional properties described here:

https://json-schema.org/understanding-json-schema/reference/combining.html

I'll probably have to go with a workaround such as this:

https://stackoverflow.com/questions/22689900/json-schema-allof-with-additionalproperties

Seems it will mess a bit with where the properties are displayed in a Swagger UI viewer, but if I can get the needed behavior, I'll live with that.

Sorry for the false alarm! :(

@thetumper
Copy link
Author

thetumper commented Nov 15, 2019

Drat. That doesn't work. When I move the property restriction out, an invalid property is not caught. The invalid data is seen as "extra" properties on the other sub-schema, which doesn't have restrictions/criteria for them. I'll commit an updated schema and test showing that. Although...this seems to be more of an Ajv or general problem, not particular to express-openapi-validator.

@cdimascio
Copy link
Owner

cdimascio commented Nov 17, 2019

@thetumper Thanks for investigating this issue. If you believe it is an Ajv issue, please feel free to file an issue there. Perhaps link it here, so I can track progress and integrate the fix when available

@thetumper
Copy link
Author

Filed an issue on ajv:

ajv-validator/ajv#1123

It may result in "this is a known limitation of the spec", but we'll see.

Thanks!

@thetumper
Copy link
Author

@cdimascio I was able to resolve this issue with changes to the schema definitions, after finding an example on another ajv issue. My latest commit has the changes that resolved it for me, in case anyone is interested:

https://github.com/thetumper/contact-schema-validator

I'm closing this issue, as there is a resolution at least for the scenario I was trying to specify, and it is related to the JSON schema spec anyway, not this or any other particular library that validates against openapi or JSON schema.

Thanks for a great package/utility!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants