Skip to content

How to use async starlette.request functions in a synchronous endpoint #2574

@kbakk

Description

@kbakk
First check
  • I added a very descriptive title to this issue.
  • I used the GitHub search to find a similar issue and didn't find it.
  • I searched the FastAPI documentation, with the integrated search.
  • I already searched in Google "How to X in FastAPI" and didn't find any information.
  • I already read and followed all the tutorial in the docs and didn't find an answer.
  • I already checked if it is not related to FastAPI but to Pydantic.
  • I already checked if it is not related to FastAPI but to Swagger UI.
  • I already checked if it is not related to FastAPI but to ReDoc.
  • After submitting this, I commit to one of:
    • Read open issues with questions until I find 2 issues where I can help someone and add a comment to help there.
    • I already hit the "watch" button in this repository to receive notifications and I commit to help at least 2 people that ask questions in the future.
    • Implement a Pull Request for a confirmed bug.

Example

Here's a self-contained, minimal, reproducible, example with my use case:

from fastapi import FastAPI
from starlette.requests import Request
import uvicorn

app = FastAPI()

@app.post("/reports/", response_model=None)
def submit_report(request: Request):
    # access to reproduce issue
    body = request.body()

    ## workaround:
    # import asyncio
    # body = asyncio.run(request.body())

    # ... do stuff with body ...

uvicorn.run(app, host="0.0.0.0", port=8000)

# output:
# INFO:     Started server process [97531]
# INFO:     Waiting for application startup.
# INFO:     Application startup complete.
# INFO:     Uvicorn running on http://0.0.0.0:8000 (Press CTRL+C to quit)
# __main__:5: RuntimeWarning: coroutine 'Request.body' was never awaited
# RuntimeWarning: Enable tracemalloc to get the object allocation traceback
# INFO:     127.0.0.1:54472 - "POST /reports/ HTTP/1.1" 200 OK

Description

I need to access the raw request body for processing, so I'm using starlette.request.Request as suggested in the docs (and in #2460).

Run above in one terminal, and this in another curl -XPOST localhost:8000/reports/.

As seen seen above (uvicorn log output), getting RuntimeWarning: coroutine 'Request.body' was never awaited. This is because the body method is async (ref.).

Is asyncio.run(request.body()) the best (only) workaround here, if I don't want my route to be async?

Environment

  • OS: MacOS Catalina 10.15.7
  • FastAPI Version: 0.63.0
  • Python version: Python 3.7.6

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions