spec-first / connexion

Connexion is a modern Python web framework that makes spec-first and api-first development easy.
https://connexion.readthedocs.io/en/latest/
Apache License 2.0
4.49k stars 762 forks source link

connexion.request.{body, form, etc}() seem to hang #1812

Open danielbprice opened 11 months ago

danielbprice commented 11 months ago

Description

I found that connexion.request does not appear to work the way the documentation implies. It seems to hang when async methods are called (I tested form() and body()).

Expected behaviour

Given:

from pathlib import Path
import connexion
from starlette.responses import PlainTextResponse, Response

async def post_greeting(body, selfie=None) -> Response:
    form = await connexion.request.form()
    print(f"form is {form}")
    return PlainTextResponse(f"Hello body={body} selfie={selfie}!", status_code=201)

app = connexion.AsyncApp(__name__, specification_dir="spec")
app.add_api("openapi.yaml", arguments={"title": "Hello World Example"})

if __name__ == "__main__":
    app.run(f"{Path(__file__).stem}:app", port=8080)

And spec

openapi: "3.0.1"

info:
  title: Form Data
  version: "1.0"
servers:
  - url: /openapi

paths:
  /greeting:
    post:
      summary: Generate greeting
      operationId: hello.post_greeting
      requestBody:
        content:
          multipart/form-data:
            schema:
              type: object
              properties:
                name:
                  type: string
                selfie:
                  type: string
                  format: binary
              required:
                - name
                - selfie
      responses:
        200:
          description: OK

Any request to this endpoint seems to hang. The docs seem to at least imply that it's OK to access these items:

image

Actual behaviour

$ curl -F name=dave -F selfie=nah http://localhost:8080/openapi/greeting
<hangs forever>

I found https://github.com/encode/starlette/issues/495, which documents similar issues therein. I am not knowledgeable enough about the innards here to know if this is the same issue or not.

Steps to reproduce

See above.

Additional info:

Output of the commands:

RobbeSneyders commented 11 months ago

Thanks for the report @danielbprice.

These are not available because Connexion already consumes them. I agree that this is not ideal. I think it would be logical if Connexion only consumes them if you let Connexion inject them into your view function. This should be possible but requires some refactoring. For now, I added a warning to the docs in #1813.

SrSoto commented 11 months ago

Having the same problem here, but also added to the fact that our controller is autogenerated by Swagger, whose online_controller.py functions are not async :skull: . Our workaround that at least initiates the server but hangs forever when accessing the endpoint is as follows:

def my_endpoint(body):  # noqa: E501
    """<endpoint description...>
    """
    check_permission(PERMISSIONS)

    if connexion.request.mimetype == "application/json":
        body = asyncio.run(connexion.request.json())

    return my_functions(body)