요청 폼과 파일
요청 폼과 파일 (Request Forms and Files)
API를 만들다 보면 파일 업로드와 함께 폼 필드(예: 토큰 같은 것)를 한 요청 안에서 함께 받아야 할 때가 있어요. FastAPI는 이럴 때 File과 Form을 함께 선언해서, 하나의 경로 동작 안에서 파일과 폼 데이터를 동시에 처리할 수 있게 해 줘요.
출처: 공식문서
먼저 python-multipart 설치하기
파일 업로드와 폼 데이터는 브라우저가 multipart/form-data 형식으로 보내요. 이 형식을 다루려면 먼저 python-multipart 패키지부터 설치해야 해요. 이게 없으면 파일을 받을 수 없으니, 어떤 내용인지는 나중에 천천히 봐도 좋아요. 일단 설치부터 하고 넘어갈게요.
$ uv add python-multipart
File과 Form 가져오기
File, Form, 그리고 파일 객체를 담는 UploadFile을 가져와요.
from typing import Annotated
from fastapi import FastAPI, File, Form, UploadFile
app = FastAPI()
File과 Form 파라미터 정의하기
Body나 Query를 선언하던 것과 똑같은 방식으로, 파일과 폼 파라미터를 선언하면 돼요. 파일은 File(), 폼 필드는 Form()으로 표시하죠.
from typing import Annotated
from fastapi import FastAPI, File, Form, UploadFile
app = FastAPI()
@app.post("/files/")
async def create_file(
file: Annotated[bytes, File()],
fileb: Annotated[UploadFile, File()],
token: Annotated[str, Form()],
):
return {
"file_size": len(file),
"token": token,
"fileb_content_type": fileb.content_type,
}
Annotated를 쓰고 싶지 않다면, 기본값으로 File()/Form()을 주는 방식도 동일하게 동작해요.
from fastapi import FastAPI, File, Form, UploadFile
app = FastAPI()
@app.post("/files/")
async def create_file(
file: bytes = File(), fileb: UploadFile = File(), token: str = Form()
):
return {
"file_size": len(file),
"token": token,
"fileb_content_type": fileb.content_type,
}
파일과 폼 필드가 폼 데이터로 업로드되면, 그 값들이 각각의 파라미터로 들어와요. 이때 주목할 점은 일부 파일은 bytes로, 일부는 UploadFile로 선언할 수 있다는 거예요. bytes로 받으면 파일 내용이 메모리에 통째로 올라오고, UploadFile로 받으면 파일 객체가 전달돼서 content_type 같은 메타데이터에도 접근할 수 있어요.
경고
하나의 경로 동작 안에 여러 개의
File/Form파라미터를 선언할 수는 있어요. 하지만 JSON으로 받고 싶은Body필드는 같이 선언할 수 없어요. 요청 본문은application/json이 아니라multipart/form-data로 인코딩되기 때문이죠. 폼(혹은 파일)을 받는 동작에서는 본문도 폼 형식으로 오는 걸 기억해 두세요.
더 알아보기 (Learn more)
- 공식문서: Request Forms and Files
- 폼만 다루기: Request Forms
- 파일만 다루기: Request Files