[FastAPI] File Upload 구현하기

천우산__ ㅣ 2024. 2. 14. 21:49

클라이언트로부터 request body를 통해 요청한 데이터를 받아서 처리할 수 있다.

이를 위한 프론트엔드 코드 예시는 아래와 같다.

import axios from "axios";


const Request = async() => {
	
    const postData = {
    	name: name,
        age: age
    };
    
    const response = await axios.post("API END-POINT", 
    	{...postData}, { headers: { "Content-Type": "application/json" } });
      
	return response.data
}

 

서버에서는 각 항목을 받고, 데이터를 처리 해야하는데

그 전에 요청받은 데이터가 처리하기 위한 규칙에 맞게 들어왔는지 확인하는 작업이 필요하다.

FastAPI 에서는 아래와 같이 검사를 위한 models.py를 만들어 주었다.

# user_models.py

from pydantic import BaseModel

class User_Resquest(BaseModel):
    name: str
    age: int

 

이 파일을 활용해서 요청된 데이터를 검사한다.

@router.post('/point') # 알맞은 END-POINT 입력

from models.users import User_Request # models.py 호출

def regist_user(user_data: User_Request):
    name = user_data.name
    age = user_data.age
    
    data = {name: user}
    return data

 

데이터를 받다 보면 문자열이나 숫자 같은 데이터 타입이 외 파일 등을 주고 받아야 할 필요가 발생할 수 있다.

이 경우에는 프론트엔드에서 파일을 보내면서

1. 데이터 요청을 위해 FormData를 사용해야 하며

2. Content-Type 을 수정 해 주어야 한다 ( application/json  -> multipart/form-data )

아래는 이름과 나이에 추가적으로 이미지 사진을 Post 요청한다고 가정한다.

import axios from "axios";


const Request = async() => {
	
    const postData = {
    	name: name,
        age: age
    };
    
    cosnt fileData = "파일 데이터 할당";
    
    const formPostData = new FormData(); // FormData 생성
    
    for (let [key, value] of Object.entries(postData){
    	formPostData.append(key, value);
    };
    
    formPostData.append("file", fileData);
    
    
    const response = await axios.post("API END-POINT", 
    	formPostData, { headers: { "Content-Type": "multipart/form-data" } });
      
	return response.data
}

 

FastAPI 서버에서도 약간의 변화가 필요하다. 먼저 파일을 받기 위한 패키지 설치가 필요하다

pip install multupart-python

파일을 받기 위해서는 File: Upload 파일과 같이 파일 업로드를 확인하는 구문을 추가해주면 되는데,

이전에 request body 에서 받아들인 데이터를 그대로 두면 오류가 발생한다.

 

FastAPI 서버 주소 /docs 로 들어가보면 Swaager가 나오는데 파일을 받는 기능이 추가되면서

FastAPI 상에서 user_data로 검사 받는 각 필드 항목이 기존 (name, age)과 다르게 변경(Request_User) 되어서

데이터가 들어가지 않는 문제가 발생한다

이를 해결하기 위해서는 각 개별 데이터로 받아오는 방식도 있겠으나,

request를 활용하면, 기존 models.py를 이용하면서 추가적으로 파일도 받을 수 있게 된다.

from fastapi import Request, UploadFile
from models.users import User_Request

@router.post('/point')
async def regist_user(user_data: Request, File: UploadFile): # 변경된 부분
    data_check = User_Request(**user_data)
    file_data = await file.read()
    
    return {"data": {"body": data_check, "file": file_data }}

User_Request(**user_data) 부분은 요청으로 들어온 데이터를 models.py 에 등록된 각 항목에 받게 확인하고 변환하는 과정이다

이 때, models 에서 설정한 키 값 (name 과 age) 외 데이터가 포함되어있다면, 그 데이터는 버려지게 되지만

필수로 포함되어야 하는 키 값이 없다면, 에러를 발생시키므로, try - catch 를 사용하는 편이 좋을 것 같다.