【FastAPI】ファイルのアップロード機能を作る方法

FastAPI

事前準備

今回はFastAPIでファイルのアップロード機能を作成する方法について紹介していきます。

FastAPIでファイルを扱うにはリクエストボディがmultipart/formdataになります。このmultipart/formdataをFastAPIで扱えるようにするには あらかじめpython-multipartのインストールが必要です。

pip install python-multipart

ファイルのアップロード機能を作る

FastAPIでファイルのアップロード機能を作る方法として、以下の2通りの実装方法があります。

  • Annotated[bytes, File()]でアノテーションする
  • UploadFileでアノテーションする

それぞれ紹介していきます。

Annoted[bytes, File()]

Annoted[bytes, File()] を用いたファイルのアップロード方法では下記コードのようにAnnoted[bytes, File()]でアノテーションを行います。

from fastapi import FastAPI, File
from typing import Annotated

app = FastAPI()

@app.post('/')
def file_upload(file: Annotated[bytes, File()]):
    return file.decode()

Swagger UIで確認してみると、ファイルをアップロードできるようになっています。
また、リクエストボディもapplication/jsonではなく、multipart/form-dataとなっています。

実際に下記のテキストファイルを与えてみます。

THIS IS TEST TEXT...

レスポンスにテキストファイルの内容が返ってきており、ちゃんとファイルをアップロードできていることがわかりました。

UploadFile

Annoted[bytes, File()]で受け取ることができていたのは、ファイルのデータでした。

一方で、UploadFileでは受け取れるものがやや異なります。

<引数>.fileで、一時的なファイルオブジェクトにアクセスできるため、データはPythonのファイルオブジェクトとして読み取ることができます。

また、データにアクセスするだけでなく、filenameでファイルの名前、content_typeでContent-typeを取得することもできます。

from fastapi import FastAPI, UploadFile

app = FastAPI()

@app.post('/')
def file_upload(file: UploadFile):
    print(file.filename)
    # test_upload.txt
    content_byte = file.file.read()
    print(file.content_type)
    # text/plain
    print(type(content_byte))
    return content_byte.decode()

実際に下記のテキストファイルを与えてみます。

THIS IS TEST TEXT...

正しく、データを読み取ることができてそうですね。

使い分け

2つのファイルのアップロード方法について紹介しましたが、これらはどのようにして使い分けるのでしょうか?

Annoted[bytes, File()]では、受け取ったデータはメモリーに保存されます。小さなサイズのファイルであれば良いですが、大きなファイルを受け取る場合、メモリーに保存するのは良くないかもしれません。

一方で、UploadFileを使用した方法では、一時ファイルとしてアクセスができるように、補助記憶に保存されています(ドキュメントによると一定程度まではメモリーに保存されるらしい)。そのため、動画などの大きなファイルをアップロードする際にはメモリーを圧迫しないようにUploadFileを使用した方が良いと言えます。

参考資料

Request Files - FastAPI
FastAPI framework, high performance, easy to learn, fast to code, ready for production

コメント