FastAPI Form Data File Fix
In this tutorial, you'll learn about FastAPI Form Data File Fix. We cover key concepts, practical examples, and best practices.
The Problem
A form that submits text fields (name, email) alongside a file (avatar) requires parsing multipart form data. FastAPI handles this with Form and File but mixing them incorrectly causes errors.
Quick Fix
Wrong — using JSON body for file uploads
from fastapi import FastAPI
from pydantic import BaseModel
class UserCreate(BaseModel):
name: str
email: str
avatar: str # Can't send files as JSON string
@app.post("/users")
async def create_user(user: UserCreate):
...
Output: Can't upload binary file data via JSON. Client must base64-encode, which increases size by 33%.
Correct — Form + File together
from fastapi import FastAPI, File, UploadFile, Form
app = FastAPI()
@app.post("/users")
async def create_user(
name: str = Form(...),
email: str = Form(...),
avatar: UploadFile = File(...),
):
contents = await avatar.read()
# Save to disk or cloud storage
avatar_url = await save_avatar(avatar.filename, contents)
user = await db.execute(
"INSERT INTO users (name, email, avatar_url) VALUES (?, ?, ?)",
(name, email, avatar_url),
)
return {"id": user.id, "name": name, "email": email, "avatar_url": avatar_url}
Output: Client sends multipart/form-data with text fields and binary file. All parsed correctly.
Multiple files with form fields
from typing import List
@app.post("/gallery")
async def upload_gallery(
title: str = Form(...),
description: str = Form(...),
images: List[UploadFile] = File(...),
):
urls = []
for image in images:
url = await save_image(image)
urls.append(url)
return {"title": title, "images": urls}
Optional file with form data
@app.post("/profile")
async def update_profile(
display_name: str = Form(...),
bio: str = Form(default=""),
avatar: UploadFile = File(None), # Optional
):
avatar_url = None
if avatar and avatar.filename:
avatar_url = await save_avatar(avatar)
return {"display_name": display_name, "avatar_url": avatar_url}
Testing form + file endpoints
from fastapi.testclient import TestClient
def test_create_user():
client = TestClient(app)
response = client.post(
"/users",
data={"name": "John", "email": "john@example.com"},
files={"avatar": ("avatar.jpg", b"image_data", "image/jpeg")},
)
assert response.status_code == 200
Prevention
- Use
Form(...)for text fields andFile(...)orUploadFilefor file fields. - Declare all form parameters as function arguments — don't mix with Pydantic models for form data.
- Use
File(None)for optional file uploads.
Common Mistakes with form data file
- Using
returnto exit a function early instead of wrapping a pure value in the monad - Mixing let bindings with <- bindings in do notation, producing type errors
- Overlapping type class instances that cause GHC to reject the program with ambiguous dispatch errors
These mistakes appear frequently in real-world FASTAPI code. DodaTech's contributors have identified these patterns through analysis of open-source projects and production systems.
Practice Exercise
Write a pure function that safely divides two integers using Maybe, then test it with edge cases like division by zero and negative numbers.
This exercise reinforces the concepts covered in this guide. Try implementing it before checking online solutions.
FAQ
Built by the developers of DodaTech
Doda Browser, DodaZIP & Durga Antivirus Pro