openapi-library / OpenAPIValidators

Use Jest or Chai to assert that HTTP responses satisfy an OpenAPI spec
MIT License
189 stars 35 forks source link

oneOf where more than 2 types inside an array #257

Open harveyappleton opened 2 years ago

harveyappleton commented 2 years ago

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'
  2. 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)

  3. 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!

rwalle61 commented 2 years ago

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

harveyappleton commented 2 years ago

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

rwalle61 commented 2 years ago

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

harveyappleton commented 2 years ago

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

asafMasa commented 2 years ago

@rwalle61 any progress on the oneOf issues?

asafMasa commented 2 years ago

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
rwalle61 commented 2 years ago

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 😁)