opticdev / optic

OpenAPI linting, diffing and testing. Optic helps prevent breaking changes, publish accurate documentation and improve the design of your APIs.
https://useoptic.com
MIT License
1.35k stars 79 forks source link

Optic is failing to parse API spec that has Anchor/Aliases #2826

Closed corneliu-petrescu closed 5 months ago

corneliu-petrescu commented 5 months ago

Describe the bug For our scenario, we are parsing specs that employ anchors and aliases as a way to reduce code.

In newer optic versions we noticed that this fails with an internal error such as:

 invalid openapi: paths > /users > post must NOT have additional properties
252 |               $ref: '.....'
253 |               required: ['jsonapi', 'data', 'links']
254 |               additionalProperties: false
255 |     <<: *error-responses
notnmeyer commented 5 months ago

was there an earlier version of optic where this was working? if so, which version worked and which version are you using currently?

corneliu-petrescu commented 5 months ago

Old optic version is 0.28.2 (this had the bulk-compare command) New optic version we are using is 0.54.5 (this is using the diff-all command)

niclim commented 5 months ago

It looks like the validation error here is saying that paths > /users > post has additional properties. Can you paste the definition of that operation (at paths > /users > post)?

It seems like there might be some additional field that is causing validation to fail, e.g.

paths:
  /users:
    post:
      ...
      invalid_extra_key: here <- this would be where the validation is catching an error

This also could be that a reference (i.e. $ref) includes an extra / additional field.

Failing that, you can turn off strict validation optic diff-all --validation loose

corneliu-petrescu commented 5 months ago

Hi I've attached 2 examples to help reproduce the issue. I've also commented out the pieces of code that make the code work. Optic: 0.54.2

Example 1: responses must NOT have additional properties

info:
  title: Example
  version: 3.0.0
servers:
  - url: /rest
    description: service-sample
tags:
  - name: Item
    description: A Item
components:
  x-location: &location
    location:
      schema:
        type: string
  x-500-response: &500-response
    '500':
      description: test
      content:
        application/vnd.api+json:
          schema:
            type: object
  parameters:
    ItemId:
      name: item_id
      in: path
      required: true
      description: uuid
      schema:
        type: string
        format: uuid

paths:
  /items/{item_id}:
    get:
      summary: Get an item
      description: Get am item
      operationId: getItem
      tags:
        - Item
      parameters:
        - $ref: '#/components/parameters/ItemId'
      responses:
        '200':
          description: Returns an item
          headers:
            location:
              schema:
                type: string
          content:
            application/vnd.api+json:
              schema:
                type: object
        # '500':
        #   description: test
        #   content:
        #     application/vnd.api+json:
        #       schema:
        #         type: object
        <<: *500-response

Example2: Cannot read properties of undefined (reading 'find')

  openapi: 3.0.3
info:
  title: Example
  version: 3.0.0
servers:
  - url: /rest
    description: service-sample
tags:
  - name: Item
    description: A Item
components:
  x-location: &location
    location:
      schema:
        type: string
  x-500-response: &500-response
    "500":
      description: test
      content:
        application/vnd.api+json:
          schema:
            type: object
  parameters:
    ItemId:
      name: item_id
      in: path
      required: true
      description: uuid
      schema:
        type: string
        format: uuid
paths:
  /items/{item_id}:
    get:
      summary: Get an item
      description: Get an item
      operationId: getItem
      tags:
        - Item
      parameters:
        - $ref: "#/components/parameters/ItemId"
      responses:
        "200":
          description: Returns an item
          headers:
            <<: *location
            # location:
            #   schema:
            #     type: string
          content:
            application/vnd.api+json:
              schema:
                type: object
        "500":
          description: test
          content:
            application/vnd.api+json:
              schema:
                type: object
niclim commented 5 months ago

Ok I see - thanks for sharing the examples. It looks like you are using the << merge mapping key which appears to be unsupported with the yaml library we are using. Doing some digging it looks like it's defined in the YAML 1.1 spec but it looks like it has been removed in later YAML specs https://yaml.org/spec/1.2.2/ext/changes/#changes-in-version-12-revision-120-2009-07-21

What I'd suggest here is to instead use $ref keys to reuse component definitions instead of using the << merge key. So for the 500 response example it might look like:

components:
  x-500-response:
    description: test
    content:
      application/vnd.api+json:
        schema:
          type: object
...
responses:
  "500":
    $ref: "#/components/x-500-response"