Using UploadFile for direct file upload without a multipart/form-data request
Question:
I have an FastAPI endpoint for handling file uploads that looks something like this:
@app.post('/upload')
async def accept_some_file(f: UploadFile):
content = await f.read()
# ... do stuff with content and generate a response
but this appears to only work with multipart/form-data
encoded payloads.
I’d like to be able to send file bytes directly through a request that looks like this:
POST /upload HTTP/1.1
Host: localhost:8080
User-Agent: curl/7.79.1
Accept: */*
Content-Type: image/jpeg
Content-Length: 11044
... image bytes
Is there a FastAPI setting I can use to allow this? Or is there another request type that makes more sense for this use case?
Answers:
You can get the request body as bytes
using await request.body()
. If you would like to do that in the synchronous way (i.e., using def
endpoint instead, see here for def
vs async def
), please have a look at this answer.
from fastapi import Request
@app.post('/upload')
async def accept_some_file(request: Request):
body = await request.body()
or, you can also access the request body as a stream, as described in this answer (under "Update" section). In this way, the byte chunks are provided without storing the entire body to memory—see Starlette documentation. Example:
@app.post('/upload')
async def accept_some_file(request: Request):
body = b''
async for chunk in request.stream():
body += chunk
I have an FastAPI endpoint for handling file uploads that looks something like this:
@app.post('/upload')
async def accept_some_file(f: UploadFile):
content = await f.read()
# ... do stuff with content and generate a response
but this appears to only work with multipart/form-data
encoded payloads.
I’d like to be able to send file bytes directly through a request that looks like this:
POST /upload HTTP/1.1
Host: localhost:8080
User-Agent: curl/7.79.1
Accept: */*
Content-Type: image/jpeg
Content-Length: 11044
... image bytes
Is there a FastAPI setting I can use to allow this? Or is there another request type that makes more sense for this use case?
You can get the request body as bytes
using await request.body()
. If you would like to do that in the synchronous way (i.e., using def
endpoint instead, see here for def
vs async def
), please have a look at this answer.
from fastapi import Request
@app.post('/upload')
async def accept_some_file(request: Request):
body = await request.body()
or, you can also access the request body as a stream, as described in this answer (under "Update" section). In this way, the byte chunks are provided without storing the entire body to memory—see Starlette documentation. Example:
@app.post('/upload')
async def accept_some_file(request: Request):
body = b''
async for chunk in request.stream():
body += chunk