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

openapi.json cannot be delivered after calling an endpoint with a $ref request body #2029

Open
bene1618 opened this issue Jan 17, 2025 · 4 comments

Comments

@bene1618
Copy link

Problem description

When creating a Connexion app with an OpenAPI spec which uses $ref to reference the request body schema, requesting /openapi.json leads to an error after the endpoint which uses $ref in the specification has been called.

Minimal example

  • Install connexion["swagger-ui"] (and uvicorn for serving), and paste the files below.
  • Run the app with uvicorn run:app
  • Navigate to Swagger UI: http://localhost:8000/ui and confirm that everything looks good
  • Call the /greeting endpoint
  • Reload Swagger UI, which leads to an error (see below)

Contents of openapi.yaml:

openapi: "3.0.0"
info:
  title: Greeting application
  version: 0.0.1
paths:
  /greeting:
    post:
      operationId: run.post_greeting
      responses:
        '200':
          description: "Greeting response"
          content:
            text/plain:
              schema:
                type: string
      requestBody:
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/Test'
components:
  schemas:
    Test:
      type: object
      properties:
        name:
          type: string
          description: A name

Contents of run.py:

from connexion import AsyncApp

app = AsyncApp(__name__)

def post_greeting(body):
    return f"Hello {body['name']}", 200

app.add_api("openapi.yaml")

Error message

connexion.exceptions.InvalidSpecification: {'content': {'application/json': {'schema': {'type': 'object', 'properties': {'name': {'type': 'string', 'description': 'A name'}}, 'components': {'schemas': {'Test': {'type': 'object', 'properties': {'name': {'type': 'string', 'description': 'A name'}}}}}}}}} is not valid under any of the given schemas

Failed validating 'oneOf' in schema['properties']['paths']['patternProperties']['^\\/']['patternProperties']['^(get|put|post|delete|options|head|patch|trace)$']['properties']['requestBody']:
    {'oneOf': [{'$ref': '#/definitions/RequestBody'},
               {'$ref': '#/definitions/Reference'}]}

On instance['paths']['/greeting']['post']['requestBody']:
    {'content': {'application/json': {'schema': {'type': 'object',
                                                 'properties': {'name': {'type': 'string',
                                                                         'description': 'A '
                                                                                        'name'}},
                                                 'components': {'schemas': {'Test': {'type': 'object',
                                                                                     'properties': {'name': {'type': 'string',
                                                                                                             'description': 'A '
                                                                                                                            'name'}}}}}}}}}

More details

The issue seems to be that #2002 returns the processed OpenAPI spec, which contains a components key inside the schema, so that the OpenAPI schema validator complains (correctly) about an invalid spec and /openapi.json refuses to deliver the spec. In fact, some testing shows that reverting bb48fb3 fixes the issue.

I'm not really sure but this might be related to the discussion in #1829.

Sample test

Something like the following might work as an integration test with the openapi.yaml from above (I used this for finding bb48fb3; maybe this helps):

from connexion import AsyncApp
from os import path

def post_greeting(body):
    return f"Hello {body['name']}", 200

def test_esoteric_error():
    app = AsyncApp(__name__)
    app.add_api(path.join(path.dirname(__file__), "fixtures/simple/esoteric-error.yaml"))

    client = app.test_client()

    response = client.get("/openapi.json")
    assert response.status_code == 200

    response = client.post("/greeting", data={"name": "XYZ"}, headers={"Content-Type": "application/json"})
    # assert response.status_code == 200 <-- returns Bad Request for some reason I didn't investigate; however it's sufficient to reproduce the error

    response = client.get("/openapi.json")
    assert response.status_code == 200
@skibbi
Copy link

skibbi commented Jan 21, 2025

I have a similar error - spec validation failing with components appearing out of nowhere alongside properties and type in requestBody - but I don't have a $ref in requestBody, only in responses" So I don't think that the $ref in requestBody is the cause.

@jhuot9
Copy link

jhuot9 commented Jan 22, 2025

I have the same problem with the migration to connection 3

@my-master
Copy link

Same here. Looks like this was introduced in the latest release. As a workaround, downgrading from connexion==3.2.0 to connexion==3.1.0 resolved it for me.

@mweigel
Copy link

mweigel commented Feb 4, 2025

Can confirm I've hit this with Connexion 3.2.0 as well. Rolling back to Connexion 3.1.0 fixes it for now.

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

5 participants