FastAPI는 HTML 폼 데이터(Form)와 파일 업로드(File/UploadFile)를 처리합니다. 이는 다른 콘텐츠 타입(multipart/form-data)을 사용하므로 JSON 본문과 구별됩니다. 둘 다 특수 매개변수 타입으로 선언됩니다.
from fastapi import Form
@app.post("/login")
def login(username: str = Form(), password: str = Form()): # JSON이 아닌 폼 필드
# 데이터는 application/x-www-form-urlencoded 또는 multipart/form-data로 옴
return {"username": username}
Form()을 사용해 HTML 폼 필드(예: 로그인 폼)를 받습니다. 참고: 라우트는 JSON 본문 또는 폼 데이터 중 하나만 사용할 수 있으며, 둘 다는 안 됩니다. 서로 다른 콘텐츠 타입이기 때문입니다. (python-multipart 설치 필요.)
from fastapi import File, UploadFile
@app.post("/upload")
async def upload(file: UploadFile): # 단일 파일
contents = await file.read() # 파일의 바이트를 읽음
file.filename # 원래 이름
file.content_type # MIME 타입
# 저장:
with open(f"uploads/{file.filename}", "wb") as f:
f.write(contents)
return {"filename": file.filename, "size": len(contents)}
UploadFile은 권장되는 타입입니다. spooled 파일(큰 파일은 메모리가 아닌 디스크로 감)이며, async 메서드(read, write, seek)와 메타데이터를 가집니다. 아주 작은 파일을 제외하고는 원시 bytes보다 이것을 사용하세요.
@app.post("/upload-many")
async def upload_many(files: list[UploadFile]): # 다중 파일
return [f.filename for f in files]
@app.post("/profile")
async def profile(name: str = Form(), avatar: UploadFile = File()):
# 하나의 multipart 요청에서 폼 필드와 파일 업로드를 결합
...
if file.content_type not in ["image/jpeg", "image/png"]: # 타입 검사
raise HTTPException(400, "Invalid file type")
# 또한: 파일 크기 제한, 파일명 정제(sanitize), 콘텐츠 스캔 — 업로드는 신뢰할 수 없는 입력
폼 데이터와 파일 업로드를 처리하는 것은 흔하고 실용적인 필요입니다. 로그인 폼, 프로필 사진 업로드, 문서 제출, 파일 처리 API가 모두 이를 요구하며, FastAPI가 기본으로 사용하는 JSON 본문과는 다르게 동작합니다.
폼 필드를 위한 Form()과 특히 업로드를 위한 UploadFile(권장 방식 — 모든 것을 메모리에 로드하는 대신 큰 파일을 디스크로 spool하므로, RAM을 소진하지 않고 큰 파일을 처리하는 데 중요함)을 이해하는 것이 이러한 기능에 필요합니다.
마찬가지로 중요한 것은 업로드에 따르는 보안 책임입니다: 업로드된 파일은 신뢰할 수 없는 입력이므로, 타입과 크기를 검증하고, 파일명을 정제하며, 저장/제공 방식에 주의하는 것이 취약점을 피하는 데 필수적입니다.
폼 필드를 받고, 단일 및 다중 파일 업로드를 처리하며, 폼과 파일을 결합하고, 업로드를 안전하게 검증하는 방법을 아는 것은 사용자가 제출하는 콘텐츠를 받는 실제 API를 구축하기 위한 실용 지식입니다.
주니어부터 시니어까지 상세한 답변이 포함된 IT 면접 질문 라이브러리.
후원하기