OpenAPIValidators icon indicating copy to clipboard operation
OpenAPIValidators copied to clipboard

oneOf where more than 2 types inside an array

Open harveyappleton opened this issue 4 years ago • 7 comments

Are you using jest or chai? Jest

Are you using OpenAPI 2, 3.0.X, or 3.1.0? OpenAPI 3.0.3

Describe the bug clearly When I use oneOf for items in an array with more than 2 distinct references, it fails randomly and can't discriminate which is the matched entity type (even with discriminator property).

Steps to reproduce the bug:

  1. Create an open api spec with oneOf with more than 2 - for example
List:
  type: array
  items: 
    oneOf:
      - $ref: '#/components/schemas/Account'
      - $ref: '#/components/schemas/Item'
      - $ref: '#/components/schemas/Payment'
  1. From an endpoint, return this array with a mix of these 3 entities, eg
[
   { type: 'Account' },
   { type: 'Item' },
   { type: 'Payment' }
]

(my actual entities are more complex than this, but for the sake of a simple bug description, this will suffice)

  1. It fails on 1 of the 3 entity types, if I remove one and only do 2 entity types then it is fine.

What did you expect to happen instead? It validates the array correctly

Are you going to resolve the issue? If I'm pointed in the right direction I may be able to!

harveyappleton avatar Nov 03 '21 12:11 harveyappleton

Thanks for raising this @harveyappleton 🙂

I may have time next weekend to look at this. In the meantime if you'd like to recreate this using this file: https://github.com/openapi-library/OpenAPIValidators/blob/master/packages/jest-openapi/test/bugRecreationTemplate.test.ts (just clone the repo and post a link to your branch here). That will help speed up my investigation

rwalle61 avatar Nov 06 '21 13:11 rwalle61

Hey @rwalle61 - think I might have found cause of issue AND produced a demo

https://github.com/harveyappleton/OpenAPIValidators/tree/master

Clone this fork Go into project cd packages/jest-openapi yarn test

You should see the failing test

● Recreate bug (issue #257) › passes

    expect(received).toSatisfyApiSpec() // Matches 'received' to a response defined in your API spec, then validates 'received' against it

    expected received to satisfy the '200' response defined for endpoint 'GET /recreate/bug' in your API spec

    received did not satisfy it because: included/1/type must be equal to one of the allowed values, included/1/attributes must have required property 'rating', included/1/attributes must NOT have additional properties, included/1/type must be equal to one of the allowed values, included/1/type must be equal to one of the allowed values, included/1/attributes must have required property 'description', included/1/attributes must NOT have additional properties, included/1 must match exactly one schema in oneOf, included/3/type must be equal to one of the allowed values, included/3/attributes must have required property 'rating', included/3/attributes must NOT have additional properties, included/3/type must be equal to one of the allowed values, included/3/type must be equal to one of the allowed values, included/3/attributes must have required property 'description', included/3/attributes must NOT have additional properties, included/3 must match exactly one schema in oneOf

    received contained: {
      body: {
        included: [
          { type: 'Apple', attributes: { rating: 5 } },
          { type: 'AppleOrange', attributes: { isTasty: true } },
          {
            type: 'Banana',
            attributes: { description: 'Yellow and sumptuous' }
          },
          { type: 'AppleOrange', attributes: { isTasty: false } },
          {
            type: 'Banana',
            attributes: { description: 'Another thing about a banana' }
          }
        ]
      }
    }

It is because it seems to match AppleOrange as Apple, perhaps it is using some sort of string starts with method? Rather than matching the entire string??

If you change AppleOrange to Orange (in both the test file and schema), it will pass!

Schema & test file are in: OpenAPIValidators/blob/master/packages/jest-openapi/__test__ on my branch.

Hope that helps

harveyappleton avatar Nov 09 '21 12:11 harveyappleton

Thanks @harveyappleton ! I didn't have time to investigate this weekend but you've given me a great starting point for when I can. Seems like something odd is happening

rwalle61 avatar Nov 14 '21 23:11 rwalle61

No problems @rwalle61 - if you can point me in the right direction, I might be able to do a fix for this :)

harveyappleton avatar Nov 25 '21 16:11 harveyappleton

@rwalle61 any progress on the oneOf issues?

asafMasa avatar Jan 25 '22 15:01 asafMasa

I have similar problem with the following:

received did not satisfy it because: response must match exactly one schema in oneOf

received contained: { body: { id: 'e1b051bf-e12e-4c1f-a257-f9de2de8bbfb' } } 

OpenAPI:
The '201' response defined for endpoint 'POST /jobs/{myId}/foos' in API spec: {
  '201': {
    description: 'Foo created successfully',
    content: {
      'application/json': {
        schema: {
          oneOf: [
            { '$ref': '#/components/schemas/createFooResponse' },
            {
              '$ref': '#/components/schemas/createMultipleFoosResponse'
            }
          ]
        }
      }
    }
  }
}

createFooResponse:
  type: object
  properties:
    id:
      $ref: '#/components/schemas/fooId'
createMultipleFoosResponse:
  type: object
  properties:
    ids:
      type: array
      items:
        $ref: '#/components/schemas/fooId'
        
fooId:
  type: string
  format: uuid

asafMasa avatar Jan 25 '22 15:01 asafMasa

Sorry I don't have time to investigate this further, happy for someone else to take a closer look 🙂 we parse the OpenAPI spec and pass the schemas to a 3rd party validator (openapi-response-validator) so it would be good to confirm if the bug is in our code or theirs (in my experience, it is probably ours 😁)

rwalle61 avatar Mar 07 '22 10:03 rwalle61