As per the documentation, "files will be uploaded as form
data", and you should receive them by either declaring the type in your endpoint as bytes
or UploadFile
(see this answer and this answer). If you need to send additional data along with the file (e.g., form
or JSON data), you may have a look at this answer as well.
If, however, you need to do that in the way you approach the problem in your question, i.e., by parsing the raw request body using request.form()
, have a look at Option 1 of this answer and the example below. As per Starlette's documentation, you can get the filename and the contents as shown below. Whatever key names are used to declare the data on client side, you have to use the same key names on server side as well, in order to retrieve the data from the form
. Below file
is used as the key for the file data.
@app.post('/upload')
async def create_file(request: Request):
form = await request.form()
filename = form['file'].filename
contents = await form['file'].read()
However, it might be best to declare the expected parameters (e.g., files and form data) in your endpoint instead of using request.form()
, as it would allow you to define whether or not a parameter should be required (hence, an exception would be raised in case a client does not include such a parameter in their request), as well as their type (i.e., str
, int
, etc.), which, again, would raise an exception if the client request does not include the data in the correct type. If you define the endpoint with async def
, then you could use aiofiles
, as shown here, to save the file to disk; otherwise, see this answer.
Upload Single File via HTML form
from fastapi import FastAPI, Request, UploadFile, HTTPException, status
from fastapi.responses import HTMLResponse
import aiofiles
app = FastAPI()
@app.post('/upload')
async def upload(file: UploadFile):
try:
contents = await file.read()
async with aiofiles.open(file.filename, 'wb') as f:
await f.write(contents)
except Exception:
raise HTTPException(
status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
detail='There was an error uploading the file',
)
finally:
await file.close()
return {'message': f'Successfuly uploaded {file.filename}'}
# Access the form at 'http://127.0.0.1:8000/' from your browser
@app.get('/')
async def main():
content = '''
<body>
<form action='/upload' enctype='multipart/form-data' method='post'>
<input name='file' type='file'>
<input type='submit'>
</form>
</body>
'''
return HTMLResponse(content=content)
Upload Multiple Files via HTML form
from fastapi import FastAPI, Request, UploadFile, HTTPException, status
from fastapi.responses import HTMLResponse
from typing import List
import aiofiles
app = FastAPI()
@app.post('/upload')
async def upload(files: List[UploadFile]):
for file in files:
try:
contents = await file.read()
async with aiofiles.open(file.filename, 'wb') as f:
await f.write(contents)
except Exception:
raise HTTPException(
status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
detail='There was an error uploading the file(s)',
)
finally:
await file.close()
return {'message': f'Successfuly uploaded {[file.filename for file in files]}'}
# Access the form at 'http://127.0.0.1:8000/' from your browser
@app.get('/')
async def main():
content = '''
<body>
<form action='/upload' enctype='multipart/form-data' method='post'>
<input name='files' type='file' multiple>
<input type='submit'>
</form>
</body>
'''
return HTMLResponse(content=content)