Using async def
endpoint
If an object is a co-routine, it needs to be awaited. FastAPI is actually Starlette underneath, and Starlette methods for returning the request body
are async
methods (see the source code here as well); thus, one needs to await
them (inside an async def
endpoint). For example:
from fastapi import Request
@app.post("/input")
async def input_request(request: Request):
return await request.body()
Update 1 - Using def
endpoint
Alternatively, if you are confident that the incoming data is a valid JSON
, you can define your endpoint with def
instead, and use the Body
field, as shown below (for more options on how to post JSON
data, see this answer):
from fastapi import Body
@app.post("/input")
def input_request(payload: dict = Body(...)):
return payload
If, however, the incoming data are in XML
format, as in the example you provided, one option is to pass them using Files
instead, as shown below—as long as you have control over how client data are sent to the server (have a look here as well). Example:
from fastapi import File
@app.post("/input")
def input_request(contents: bytes = File(...)):
return contents
Update 2 - Using def
endpoint and async
dependency
As described in this post, you can use an async
dependency function to pull out the body
from the request. You can use async
dependencies on non-async
(i.e., def
) endpoints as well. Hence, if there is some sort of blocking code in this endpoint that prevents you from using async
/await
—as I am guessing this might be the reason in your case—this is the way to go.
Note: I should also mention that this answer—which explains the difference between def
and async def
endpoints (that you might be aware of)—also provides solutions when you are required to use async def
(as you might need to await
for coroutines inside a route), but also have some synchronous expensive CPU-bound operation that might be blocking the server. Please have a look.
Example of the approach described earlier can be found below. You can uncomment the time.sleep()
line, if you would like to confirm yourself that a request won't be blocking other requests from going through, as when you declare an endpoint with normal def
instead of async def
, it is run in an external threadpool (regardless of the async def
dependency function).
from fastapi import FastAPI, Depends, Request
import time
app = FastAPI()
async def get_body(request: Request):
return await request.body()
@app.post("/input")
def input_request(body: bytes = Depends(get_body)):
print("New request arrived.")
#time.sleep(5)
return body