Browse Source
This PR adds practical examples for validating and saving uploaded files, addressing common production use cases. New examples: - Tutorial 004: Upload with validation (file type, size, count) - Tutorial 005: Saving files to disk with unique names Each example includes variants for Python 3.9+ and 3.10+. Documentation updated with new sections explaining validation best practices and file saving security considerations.pull/14327/head
7 changed files with 348 additions and 0 deletions
@ -0,0 +1,43 @@ |
|||
from typing import List |
|||
|
|||
from fastapi import FastAPI, File, HTTPException, UploadFile |
|||
|
|||
app = FastAPI() |
|||
|
|||
|
|||
@app.post("/upload-images/") |
|||
async def upload_images( |
|||
files: List[UploadFile] = File(description="Multiple images"), |
|||
): |
|||
allowed_types = ["image/jpeg", "image/png", "image/gif", "image/webp"] |
|||
max_size = 5 * 1024 * 1024 # 5MB |
|||
|
|||
if len(files) > 10: |
|||
raise HTTPException(status_code=400, detail="Too many files") |
|||
|
|||
results = [] |
|||
|
|||
for file in files: |
|||
if file.content_type not in allowed_types: |
|||
raise HTTPException( |
|||
status_code=400, |
|||
detail=f"Invalid file type: {file.content_type}", |
|||
) |
|||
|
|||
contents = await file.read() |
|||
if len(contents) > max_size: |
|||
raise HTTPException( |
|||
status_code=400, detail=f"File too large: {file.filename}" |
|||
) |
|||
|
|||
await file.seek(0) |
|||
|
|||
results.append( |
|||
{ |
|||
"filename": file.filename, |
|||
"content_type": file.content_type, |
|||
"size": len(contents), |
|||
} |
|||
) |
|||
|
|||
return {"uploaded": len(results), "files": results} |
|||
@ -0,0 +1,43 @@ |
|||
from typing import Annotated |
|||
|
|||
from fastapi import FastAPI, File, HTTPException, UploadFile |
|||
|
|||
app = FastAPI() |
|||
|
|||
|
|||
@app.post("/upload-images/") |
|||
async def upload_images( |
|||
files: Annotated[list[UploadFile], File(description="Multiple images")], |
|||
): |
|||
allowed_types = ["image/jpeg", "image/png", "image/gif", "image/webp"] |
|||
max_size = 5 * 1024 * 1024 # 5MB |
|||
|
|||
if len(files) > 10: |
|||
raise HTTPException(status_code=400, detail="Too many files") |
|||
|
|||
results = [] |
|||
|
|||
for file in files: |
|||
if file.content_type not in allowed_types: |
|||
raise HTTPException( |
|||
status_code=400, |
|||
detail=f"Invalid file type: {file.content_type}", |
|||
) |
|||
|
|||
contents = await file.read() |
|||
if len(contents) > max_size: |
|||
raise HTTPException( |
|||
status_code=400, detail=f"File too large: {file.filename}" |
|||
) |
|||
|
|||
await file.seek(0) |
|||
|
|||
results.append( |
|||
{ |
|||
"filename": file.filename, |
|||
"content_type": file.content_type, |
|||
"size": len(contents), |
|||
} |
|||
) |
|||
|
|||
return {"uploaded": len(results), "files": results} |
|||
@ -0,0 +1,43 @@ |
|||
from typing import Annotated |
|||
|
|||
from fastapi import FastAPI, File, HTTPException, UploadFile |
|||
|
|||
app = FastAPI() |
|||
|
|||
|
|||
@app.post("/upload-images/") |
|||
async def upload_images( |
|||
files: Annotated[list[UploadFile], File(description="Multiple images")], |
|||
): |
|||
allowed_types = ["image/jpeg", "image/png", "image/gif", "image/webp"] |
|||
max_size = 5 * 1024 * 1024 # 5MB |
|||
|
|||
if len(files) > 10: |
|||
raise HTTPException(status_code=400, detail="Too many files") |
|||
|
|||
results = [] |
|||
|
|||
for file in files: |
|||
if file.content_type not in allowed_types: |
|||
raise HTTPException( |
|||
status_code=400, |
|||
detail=f"Invalid file type: {file.content_type}", |
|||
) |
|||
|
|||
contents = await file.read() |
|||
if len(contents) > max_size: |
|||
raise HTTPException( |
|||
status_code=400, detail=f"File too large: {file.filename}" |
|||
) |
|||
|
|||
await file.seek(0) |
|||
|
|||
results.append( |
|||
{ |
|||
"filename": file.filename, |
|||
"content_type": file.content_type, |
|||
"size": len(contents), |
|||
} |
|||
) |
|||
|
|||
return {"uploaded": len(results), "files": results} |
|||
@ -0,0 +1,55 @@ |
|||
import shutil |
|||
from pathlib import Path |
|||
from typing import List |
|||
from uuid import uuid4 |
|||
|
|||
from fastapi import FastAPI, File, HTTPException, UploadFile |
|||
|
|||
app = FastAPI() |
|||
|
|||
UPLOAD_DIR = Path("uploaded_files") |
|||
UPLOAD_DIR.mkdir(exist_ok=True) |
|||
|
|||
|
|||
@app.post("/upload-product-images/") |
|||
async def upload_product_images( |
|||
files: List[UploadFile] = File(description="Product images"), |
|||
): |
|||
allowed_types = ["image/jpeg", "image/png", "image/webp"] |
|||
max_size = 5 * 1024 * 1024 # 5MB |
|||
|
|||
if len(files) > 10: |
|||
raise HTTPException(status_code=400, detail="Too many files") |
|||
|
|||
saved = [] |
|||
|
|||
for file in files: |
|||
if file.content_type not in allowed_types: |
|||
raise HTTPException( |
|||
status_code=400, |
|||
detail=f"Invalid file type: {file.content_type}", |
|||
) |
|||
|
|||
contents = await file.read() |
|||
if len(contents) > max_size: |
|||
raise HTTPException( |
|||
status_code=400, detail=f"File too large: {file.filename}" |
|||
) |
|||
|
|||
file_ext = Path(file.filename).suffix |
|||
unique_name = f"{uuid4()}{file_ext}" |
|||
file_path = UPLOAD_DIR / unique_name |
|||
|
|||
await file.seek(0) |
|||
with file_path.open("wb") as buffer: |
|||
shutil.copyfileobj(file.file, buffer) |
|||
|
|||
saved.append( |
|||
{ |
|||
"filename": file.filename, |
|||
"saved_as": unique_name, |
|||
"size": len(contents), |
|||
} |
|||
) |
|||
|
|||
return {"uploaded": len(saved), "files": saved} |
|||
@ -0,0 +1,55 @@ |
|||
import shutil |
|||
from pathlib import Path |
|||
from typing import Annotated |
|||
from uuid import uuid4 |
|||
|
|||
from fastapi import FastAPI, File, HTTPException, UploadFile |
|||
|
|||
app = FastAPI() |
|||
|
|||
UPLOAD_DIR = Path("uploaded_files") |
|||
UPLOAD_DIR.mkdir(exist_ok=True) |
|||
|
|||
|
|||
@app.post("/upload-product-images/") |
|||
async def upload_product_images( |
|||
files: Annotated[list[UploadFile], File(description="Product images")], |
|||
): |
|||
allowed_types = ["image/jpeg", "image/png", "image/webp"] |
|||
max_size = 5 * 1024 * 1024 # 5MB |
|||
|
|||
if len(files) > 10: |
|||
raise HTTPException(status_code=400, detail="Too many files") |
|||
|
|||
saved = [] |
|||
|
|||
for file in files: |
|||
if file.content_type not in allowed_types: |
|||
raise HTTPException( |
|||
status_code=400, |
|||
detail=f"Invalid file type: {file.content_type}", |
|||
) |
|||
|
|||
contents = await file.read() |
|||
if len(contents) > max_size: |
|||
raise HTTPException( |
|||
status_code=400, detail=f"File too large: {file.filename}" |
|||
) |
|||
|
|||
file_ext = Path(file.filename).suffix |
|||
unique_name = f"{uuid4()}{file_ext}" |
|||
file_path = UPLOAD_DIR / unique_name |
|||
|
|||
await file.seek(0) |
|||
with file_path.open("wb") as buffer: |
|||
shutil.copyfileobj(file.file, buffer) |
|||
|
|||
saved.append( |
|||
{ |
|||
"filename": file.filename, |
|||
"saved_as": unique_name, |
|||
"size": len(contents), |
|||
} |
|||
) |
|||
|
|||
return {"uploaded": len(saved), "files": saved} |
|||
@ -0,0 +1,55 @@ |
|||
import shutil |
|||
from pathlib import Path |
|||
from typing import Annotated |
|||
from uuid import uuid4 |
|||
|
|||
from fastapi import FastAPI, File, HTTPException, UploadFile |
|||
|
|||
app = FastAPI() |
|||
|
|||
UPLOAD_DIR = Path("uploaded_files") |
|||
UPLOAD_DIR.mkdir(exist_ok=True) |
|||
|
|||
|
|||
@app.post("/upload-product-images/") |
|||
async def upload_product_images( |
|||
files: Annotated[list[UploadFile], File(description="Product images")], |
|||
): |
|||
allowed_types = ["image/jpeg", "image/png", "image/webp"] |
|||
max_size = 5 * 1024 * 1024 # 5MB |
|||
|
|||
if len(files) > 10: |
|||
raise HTTPException(status_code=400, detail="Too many files") |
|||
|
|||
saved = [] |
|||
|
|||
for file in files: |
|||
if file.content_type not in allowed_types: |
|||
raise HTTPException( |
|||
status_code=400, |
|||
detail=f"Invalid file type: {file.content_type}", |
|||
) |
|||
|
|||
contents = await file.read() |
|||
if len(contents) > max_size: |
|||
raise HTTPException( |
|||
status_code=400, detail=f"File too large: {file.filename}" |
|||
) |
|||
|
|||
file_ext = Path(file.filename).suffix |
|||
unique_name = f"{uuid4()}{file_ext}" |
|||
file_path = UPLOAD_DIR / unique_name |
|||
|
|||
await file.seek(0) |
|||
with file_path.open("wb") as buffer: |
|||
shutil.copyfileobj(file.file, buffer) |
|||
|
|||
saved.append( |
|||
{ |
|||
"filename": file.filename, |
|||
"saved_as": unique_name, |
|||
"size": len(contents), |
|||
} |
|||
) |
|||
|
|||
return {"uploaded": len(saved), "files": saved} |
|||
Loading…
Reference in new issue