[FastAPI Docs] 파일 요청

JeongChaeJin·2022년 9월 1일
pip install python-multipart
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}
  • 클라이언트가 업로드한 파일들을 정의할 수 있다.
  • File은 Form을 상속받은 클래스다.
    • 파일들은 Form 데이터 형태로 업로드 된다.
  • operation function 매개변수를 bytes로 선언한 경우 파일을 읽고 bytes 형태의 내용을 전달한다.
    • 작은 크기의 파일들에 적합하다.
  • UploadFile을 사용할 경우 bytes에 비해 몇가지 장점이 있다.
    • Spool File 사용
      • 최대 크기 제한까지만 메모리에 저장, 초과하는 경우 디스크에 저장
    • 이미지, 동영상, 큰 이진코드 같은 대용량 파일을 많은 메모리를 소모하지 않고 처리하기에 적합하다.
    • 업로드 된 파일의 메타데이터를 얻을 수 있다.
    • file-like async 인터페이스를 갖고있다.
    • 다른 라이브러리에 직접적으로 전달할 수 있는 SpooledtemporaryFile 객체를 반환한다.

UploadFile

  • attribute
    • filename : 문자열로 업로드된 파일의 파일명
    • content_type : 파일 형식(MIME type/media type)
    • file : SpooledTemporaryFile 객체 -> 다른 라이브러리에 직접적으로 전달할 수 있는 파이선 파일
    • write(data) : data(str or bytes)를 파일에 작성
    • read(size) : 파일의 바이트 및 size를 읽는다.
    • seek(offset) : 파일 내 offset 위치의 바이트로 이동
      • await myfile.seek(0) 사용 시 파일 시작부분으로 이동
      • await myfile.read() 사용 후 내용 다시 읽은 때 유용
    • close() : 파일 닫기
contents = await myfile.read()
  • async 경로 작동 함수의 내부에서 위 처럼 선언해서 내용을 가져올 수 있다.
  • async method 사용 시 FastAPI는 스레드 풀에서 파일 메소드들을 실행하고 결과를 기다린다.
contents = myfile.read()
  • 그냥 def 일 경우 직접 바로 접근 가능

Form Data ?

  • HTML의 <form> </form>이 서버에 데이터를 전송하는 방식은 JSON과는 다른 특별한 인코딩을 사용한다.
  • 파일이 포함되어 있지 않은 경우 일반적으로 미디어 유형으로 application/x-www-form-urlencoded를 사용해 인코딩 된다.
  • 파일이 포함된 경우 multipart/form-data로 인코딩 된다.

다중 파일 업로드

from typing import List

from fastapi import FastAPI, File, UploadFile
from fastapi.responses import HTMLResponse

app = FastAPI()


@app.post("/files/")
async def create_files(files: List[bytes] = File()):
    return {"file_sizes": [len(file) for file in files]}


@app.post("/uploadfiles/")
async def create_upload_files(files: List[UploadFile]):
    return {"filenames": [file.filename for file in files]}


@app.get("/")
async def main():
    content = """
<body>
<form action="/files/" enctype="multipart/form-data" method="post">
<input name="files" type="file" multiple>
<input type="submit">
</form>
<form action="/uploadfiles/" enctype="multipart/form-data" method="post">
<input name="files" type="file" multiple>
<input type="submit">
</form>
</body>
    """
    return HTMLResponse(content=content)
  • bytes의 list or UploadFile들을 전송받게 된다.
profile
OnePunchLotto

0개의 댓글