【FastAPI】アップロード・ダウンロードファイルの操作

FastAPIAPIでのファイルの

  • アップロード
  • ダウンロード

方法についてご紹介いたします。

サーバーにある静的ファイルの配信方法や、エンドポイントでの認証を含めた配信方法です。

この記事のサンプルコード

目次

File

ファイルを受け取るためのクラスは主に2種類あり

  • File
  • UploadFile

があります。UploadFileFileのラッパークラスです。より使いやすく、大きなファイルでも操作可能にしたものです。両方見ていきます。

File

ファイルを受け取るには、bytesを宣言し、デフォルトとしてFileを受け取るように記述します。

def file(file: bytes = File(...)):

受けとるファイルはメモリ内に保存されるため、小さいファイルサイズのデータを受け取る際に有効です。

@router.post('/')
def get_file(file: bytes = File(...)):
    content = file.decode('utf-8')
    lines = content.split('\n')
    return {'lines': lines}

ファイルをアップロードできるエンドポイントを作成しました。

テキストファイルをサンプルとしてアップロードしてみましょう。テキストの中身を返すようにしています。

Hello FastAPI

txt file

UploadFile

前述の通り、Fileの他にUploadFileがあります。

Fileと比較するとより多くの機能を持つほか、大きいファイルサイズの画像やビデオが扱えるようになります。

def upload_file(file: UploadFile = File(...)):

UploadFilefastapiからインポートします。

アップロードされたファイル名を返すエンドポイントを作成しました。

@router.post('uploadfile')
def get_uploadfile(upload_file: UploadFile = File(...)):
    return {
        'filename': upload_file.filename
    }

filename以外にもcontent_typeが受け取れます。

class UploadFile:
    """
    An uploaded file included as part of the request data.
    """

    spool_max_size = 1024 * 1024

    def __init__(
        self, filename: str, file: typing.IO = None, content_type: str = ""
    ) -> None:
        self.filename = filename
        self.content_type = content_type
        if file is None:
            file = tempfile.SpooledTemporaryFile(max_size=self.spool_max_size)
        self.file = file

アップロードファイルの保存

アップロードファイルをローカルに保存します。

https://docs.python.org/ja/3/library/functions.html#open

https://docs.python.org/ja/3/library/shutil.html

from fastapi import UploadFile
import shutil

@router.post('uploadfile')
def get_uploadfile(upload_file: UploadFile = File(...)):
    path = f'files/{upload_file.filename}'
    with open(path, 'w+b') as buffer:
        shutil.copyfileobj(upload_file.file, buffer)
    return {
        'filename': path,
        'type': upload_file.content_type
    }

shutil.coyfileobj()でローカル上の指定フォルダにファイルがコピーされます。

このままだと、同様のファイルネームがアップロードがされた場合には上書きされてしまうため注意が必要です。

ファイルアップロードのAPIを叩いてみると・・・

下記の様に、ローカル上のfile/ディレクトリに保存されていることが確認できました。

静的ファイルを外部に配信する

アップロードしたファイルを外部に公開できるようにします。

例えば、127.0.0.1:8000/files/fastapi.pngのような形式で見れたら良いですね。

pip install aiofiles

次にmain.pyに追記していきます。

fastapi.staticfilesからStaticFilesをインポートし、app.mount()を記述します。

from fastapi.staticfiles import StaticFiles
~~~
app.mount('/files', StaticFiles(directory="files"), name='files')

http://127.0.0.1:8000/files/のアップロードしたファイル名のパスにブラウザからアクセスすると閲覧できるようになっているはずです。

ダウンロード

前述のように、ただファイルを公開するだけではなく、ダウンロードリンクとして実装します。

https://fastapi.tiangolo.com/ja/advanced/custom-response/?h=fileresponse#fileresponse

エンドポイント経由となるため、認証機能を追加したりすることが可能です。

エンドポイントの作成

fastapi.responsesからFileResponseをインポートし、response_classに指定します。

from fastapi.responses import FileResponse

~~~

@router.get('/download/{name}', response_class=FileResponse)
def get_file(name: str):
    path = f'files/{name}'
    return path

FileResponseの通り、fileが配信されています。

認証機能の追加

この状態ですと、誰でも閲覧できてしまうので認証機能をAPIに追加します。

JWT認証によるエンドポイントの保護については下記記事をご参照ください。

@router.get('/download2/{name}', response_class=FileResponse)
def get_file(name: str, current_user: str = Depends(get_current_user)):
    path = f'files/{name}'
    return path

確認してみると・・・

きちんと保護されていますね!

この記事のサンプルコード

この記事が気に入ったら
フォローしてね!

よかったらシェアしてね!

コメント

コメントする

目次
閉じる