UploadFile - single and multiple
Files# pip install python-multipart (required for File/Form)
from fastapi import File, UploadFile, HTTPException
from typing import List
import shutil, os
# UploadFile - preferred for all uploads
@app.post("/upload")
async def upload(file: UploadFile):
contents = await file.read()
return {
"filename": file.filename,
"content_type": file.content_type,
"size_bytes": len(contents)
}
# Save to disk
@app.post("/upload-save")
async def save_file(file: UploadFile):
os.makedirs("uploads", exist_ok=True)
with open(f"uploads/{file.filename}", "wb") as f:
shutil.copyfileobj(file.file, f)
return {"saved": file.filename}
# Multiple files
@app.post("/upload-many")
async def upload_many(files: List[UploadFile]):
return [{"name": f.filename, "type": f.content_type} for f in files]
# Validate file type and size
@app.post("/upload-image")
async def upload_image(file: UploadFile):
if file.content_type not in ["image/jpeg", "image/png"]:
raise HTTPException(400, "Only JPEG and PNG allowed")
contents = await file.read()
if len(contents) > 5 * 1024 * 1024:
raise HTTPException(413, "File exceeds 5MB limit")
return {"ok": True}Watch out: file.filename comes from the client. Saving to f"uploads/{file.filename}" as-is lets a name like "../main.py" escape the folder - generate your own name, or use os.path.basename and check the result.
Tip: content_type is also client-supplied. For anything security-sensitive, check the file bytes themselves rather than trusting the header.