Document Upload Service¶
A multi-file document upload endpoint using S3 storage with metadata tracking.
Full Example¶
app.py
from datetime import datetime, timezone
from fastapi import Depends, FastAPI
from filestore import FileField, FileStore, S3Engine, Store, StoreConfig, UploadContext
app = FastAPI()
def document_metadata(ctx: UploadContext) -> dict:
"""Attach request context as metadata."""
return {
"uploaded_by": ctx.request.headers.get("X-User-ID", "anonymous"),
"uploaded_at": datetime.now(timezone.utc).isoformat(),
"original_name": ctx.file.filename,
"ip": ctx.request.client.host if ctx.request.client else None,
}
storage = FileStore(
fields=[
FileField(
name="documents",
required=True,
max_count=10,
config=StoreConfig(
destination="uploads/documents",
allowed_extensions=[".pdf", ".docx", ".xlsx", ".pptx", ".txt"],
max_file_size=50 * 1024 * 1024, # 50 MB per file
),
),
],
engine=S3Engine(bucket="my-documents-bucket", region="us-east-1"),
config=StoreConfig(metadata=document_metadata),
)
@app.post("/documents")
async def upload_documents(store: Store = Depends(storage)):
return {
"status": store.status,
"uploaded": [
{
"filename": f.filename,
"url": f.url,
"key": f.key, # keep for delete / presigned downloads
"size": f.size,
"metadata": f.metadata,
}
for f in store.successful_files
],
"rejected": [
{
"filename": f.original_filename,
"error": f.error,
}
for f in store.failed_files
],
"total_size_mb": round(store.total_size / (1024 * 1024), 2),
}
Key Points¶
- Up to 10 files per request with
max_count=10 - 50 MB per file limit
- Metadata callback captures upload context for audit trails
FileData.keyis stored so documents can later be deleted (engine.delete(key)) or served viaengine.presign_download(key)- Structured response separates successes from failures