FastAPI에서 Form 데이터를 처리하려면 Form 클래스를 사용합니다. Form 데이터는 일반적으로 HTML <form> 태그를 통해 전송되는 입력 데이터입니다. JSON 데이터와는 다르게 처리되므로, FastAPI에서 이를 제대로 인식하고 처리하기 위해 Form을 사용해야 합니다.
일반적인 API는 JSON 형식의 데이터를 받지만, 때로는 HTML 폼을 통해 데이터가 전송되는 경우가 있습니다. 이 경우, FastAPI에서는 Form 클래스를 사용하여 해당 데이터를 처리합니다.
from fastapi import FastAPI, Form
from typing import Annotated
app = FastAPI()
@app.post("/login/")
async def login(username: Annotated[str, Form()], password: Annotated[str, Form()]):
return {"username": username}
이 예시에서는 username과 password를 HTML 폼 필드로 받아들입니다. 이는 JSON 본문과는 다른 방식으로 처리됩니다.
python-multipart 패키지를 설치해야 합니다.Form()은 기본적으로 Body()와 동일한 클래스에서 상속되지만, Form 데이터를 명시적으로 처리할 수 있도록 설계되었습니다.Form 데이터를 받기 위해서는, Body나 Query처럼 Form을 사용하여 입력 매개변수를 선언할 수 있습니다.
from fastapi import FastAPI, Form
from typing import Annotated
app = FastAPI()
@app.post("/login/")
async def login(username: Annotated[str, Form()], password: Annotated[str, Form()]):
return {"username": username}
이 예시에서는 OAuth2의 "password flow" 스펙에서 username과 password를 HTML 폼 필드로 받습니다. Form 클래스는 Body()와 동일한 방식으로 동작하며, 예시를 추가하거나 별칭을 설정할 수 있습니다.
HTML <form> 태그는 데이터를 전송할 때 JSON이 아닌 application/x-www-form-urlencoded 또는 multipart/form-data로 인코딩합니다. 이는 JSON과는 다른 방식이기 때문에 Form 클래스를 사용하여 해당 데이터를 처리해야 합니다.
Form 클래스를 명시적으로 사용하지 않으면, FastAPI는 해당 데이터를 Query나 Body 파라미터로 해석하게 됩니다.
Form 데이터를 받는 경로에서는 JSON 데이터와 Form 데이터를 동시에 받을 수 없습니다. 그 이유는 HTTP 프로토콜 상에서 하나의 요청 본문은 단 하나의 미디어 유형으로 인코딩되기 때문입니다. Form 데이터를 사용하면 본문은 application/x-www-form-urlencoded로 인코딩되므로, JSON 본문을 동시에 사용할 수 없습니다.
이처럼 FastAPI에서 Form 데이터를 처리할 때는 Form 클래스를 사용하여 명확하게 선언하고, JSON 데이터와는 별도로 처리해야 합니다.
FastAPI에서는 Form 데이터를 처리할 때 Pydantic 모델을 사용할 수 있습니다. 이를 통해 입력된 Form 데이터를 효과적으로 검증하고, 모델화하여 관리할 수 있습니다.
FastAPI는 Pydantic 모델을 사용하여 Form 데이터를 처리할 수 있도록 지원합니다. 이를 통해, 요청 본문 데이터를 체계적으로 선언하고 검증할 수 있습니다.
from fastapi import FastAPI, Form
from pydantic import BaseModel
from typing import Annotated
app = FastAPI()
class FormData(BaseModel):
username: str
password: str
@app.post("/login/")
async def login(data: Annotated[FormData, Form()]):
return data
어떤 경우에는 Form에 명시된 필드 외의 추가적인 필드가 전송되는 것을 방지해야 할 수 있습니다. 이를 위해 Pydantic의 모델 구성을 통해 추가 필드 금지 설정을 할 수 있습니다.
from fastapi import FastAPI, Form
from pydantic import BaseModel
from typing import Annotated
app = FastAPI()
class FormData(BaseModel):
username: str
password: str
model_config = {"extra": "forbid"}
@app.post("/login/")
async def login(data: Annotated[FormData, Form()]):
return data
위 코드에서는 model_config에 extra: "forbid" 옵션을 설정하여, 추가적인 Form 필드가 전송되지 않도록 했습니다.
만약 클라이언트가 username, password 외의 필드(예: extra)를 전송하면, 다음과 같은 에러 응답이 반환됩니다.
{
"detail": [
{
"type": "extra_forbidden",
"loc": ["body", "extra"],
"msg": "Extra inputs are not permitted",
"input": "Mr. Poopybutthole"
}
]
}
FastAPI의 /docs 경로에서 자동 생성된 API 문서에서 Pydantic 모델을 사용하여 선언된 Form 필드들을 확인할 수 있습니다. 이를 통해 API의 입력 데이터 구조를 명확하게 확인하고 테스트할 수 있습니다.
FastAPI를 사용하면 클라이언트가 업로드하는 파일을 처리할 수 있습니다. 파일들은 "폼 데이터"로 전송되며, FastAPI는 이 데이터를 처리할 수 있는 여러 방법을 제공합니다.
파일을 처리하기 위해서는 python-multipart 패키지를 설치해야 합니다. 이를 통해, FastAPI는 multipart/form-data 형식으로 전송되는 데이터를 처리할 수 있습니다.
$ pip install python-multipart
FastAPI에서 파일을 처리하기 위해서는 File과 UploadFile 클래스를 임포트해야 합니다.
from fastapi import FastAPI, File, UploadFile
app = FastAPI()
@app.post("/files/")
async def create_file(file: bytes = File()):
return {"file_size": len(file)}
@app.post("/uploadfile/")
async def create_upload_file(file: UploadFile):
return {"filename": file.filename}
파일 매개변수는 Body 및 Form과 같은 방식으로 정의할 수 있습니다.
@app.post("/files/")
async def create_file(file: bytes = File()):
return {"file_size": len(file)}
파일 업로드 시 File과 UploadFile 중 어느 것을 사용할지 결정할 수 있습니다.
@app.post("/uploadfile/")
async def create_upload_file(file: UploadFile):
return {"filename": file.filename}
UploadFile은 파일에 대한 다양한 정보와 메소드를 제공합니다:
@app.post("/uploadfile/")
async def create_upload_file(file: UploadFile):
contents = await file.read()
return {"file_contents": contents}
여러 파일을 동시에 업로드하려면 List[bytes] 또는 List[UploadFile]을 사용합니다.
from typing import List
from fastapi import FastAPI, File, UploadFile
app = FastAPI()
@app.post("/uploadfiles/")
async def create_upload_files(files: List[UploadFile]):
return {"filenames": [file.filename for file in files]}
여기서는 UploadFile 리스트를 받아 여러 파일을 처리할 수 있습니다.
파일 업로드를 테스트하기 위해 간단한 HTML 양식을 사용할 수 있습니다.
@app.get("/")
async def main():
content = """
<body>
<form action="/uploadfiles/" enctype="multipart/form-data" method="post">
<input name="files" type="file" multiple>
<input type="submit">
</form>
</body>
"""
return HTMLResponse(content=content)
이 폼을 통해 다중 파일을 선택하여 업로드할 수 있습니다.
파일 업로드와 관련된 FastAPI의 기능은 강력하고 유연하여, 다양한 파일 업로드 시나리오를 처리하는 데 매우 유용합니다.
FastAPI를 사용하면 File과 Form을 함께 처리하여 클라이언트가 전송하는 파일과 폼 데이터를 동시에 처리할 수 있습니다. 이를 통해 파일 업로드와 폼 필드 데이터를 하나의 요청으로 받을 수 있습니다.
파일과 폼 데이터를 함께 처리하려면 python-multipart 패키지를 설치해야 합니다. 이 패키지는 multipart/form-data 형식으로 전송되는 데이터를 처리하는 데 필요합니다.
$ pip install python-multipart
FastAPI에서 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,
}
이 코드에서:
Body 및 Query와 마찬가지로 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,
}
파일과 폼 데이터는 폼 데이터 형식으로 전송되며, FastAPI는 이를 자동으로 multipart/form-data로 처리하여 각 파일과 폼 필드를 적절하게 분리하여 전달합니다.
폼 데이터와 파일 데이터를 처리할 때, 한 가지 중요한 점이 있습니다:
FastAPI에서는 File과 Form 매개변수를 함께 사용하여 파일과 폼 데이터를 동시에 처리할 수 있습니다.
하나의 요청으로 파일과 폼 데이터를 처리해야 할 경우, File과 Form을 함께 사용하여 유연하고 효율적인 데이터 처리가 가능합니다.