🤖

📁 FastAPI 実践入門:第七歩目で学ぶ ファイルアップロードと画像処理の基本

に公開

🔍 はじめに

これまでのステップで、FastAPIを使った基本的なルーティング、リクエスト処理、認証・認可、CORS設定などを学んできました。第七歩目では、WebアプリケーションやAPI開発で頻出する「ファイルアップロード」と「画像ファイルの取り扱い」について実践的に学んでいきます。特に、プロフィール画像のアップロードやPDFファイルの受け取りなど、実用性の高いケースを想定した内容です。
ファイルアップロードは、単なるデータ送信にとどまらず、ユーザーがアプリに参加・関与する重要な手段です。実際のプロジェクトでは、ユーザーが提出する書類、契約書、プロフィール画像、画像加工用データなどをサーバーに送信する場面が多く、開発者にとってもその取り扱いは避けて通れない重要な機能です。

📤 ファイルアップロードの基本

FastAPIでは、File型とUploadFile型を使って簡単にファイルのアップロードが可能です。特にUploadFile型は非同期I/Oを使って効率的にファイルを扱えるため、大容量ファイルにも適しています。

✅ エンドポイントの例

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

app = FastAPI()

@app.post("/uploadfile/")
async def create_upload_file(file: UploadFile = File(...)):
    return {"filename": file.filename}

この例では、UploadFile型を使って受け取ったファイルの名前を返しています。UploadFileは非同期で動作し、ファイルをメモリではなくテンポラリファイルとして処理するため、高速でメモリ効率が良いです。

📎 フロントエンドから送信するフォーム(HTML)


<form action="/uploadfile/" enctype="multipart/form-data" method="post">
  <input name="file" type="file">
  <input type="submit">
</form>

このフォームは、ユーザーにファイルを選択させてサーバーにPOSTリクエストとして送信します。multipart/form-data を使用することで、ファイルデータが正しく送信されます。

🖼️ 画像ファイルを保存する

アップロードされた画像をサーバー内に保存したい場合、以下のように処理します。画像の保存は、プロフィール写真や商品写真の登録など、実際のサービスで頻繁に登場する機能です。

import shutil

@app.post("/savefile/")
async def save_upload_file(file: UploadFile = File(...)):
    with open(f"uploads/{file.filename}", "wb") as buffer:
        shutil.copyfileobj(file.file, buffer)
    return {"status": "保存しました", "filename": file.filename}

✅ 注意点

  • uploads/ ディレクトリが存在することを確認してください。存在しない場合は os.makedirs() で作成する処理を追加すると安全です。
  • 保存処理の前に、ファイルの拡張子やサイズなどをチェックするとより安全です。
  • 不正なファイル(例:スクリプト埋め込み)のアップロードを防ぐための対策も検討する必要があります。

🧪 ファイル形式のバリデーション

セキュリティの観点から、アップロードされたファイルの形式をチェックすることが重要です。特に画像やPDF、ドキュメントなどは、MIMEタイプと拡張子の一致も確認することでリスクを軽減できます。

from fastapi import HTTPException

@app.post("/validate-image/")
async def validate_image(file: UploadFile = File(...)):
    if not file.content_type.startswith("image/"):
        raise HTTPException(status_code=400, detail="画像ファイルをアップロードしてください")
    return {"filename": file.filename, "type": file.content_type}

このコードでは、image/で始まるMIMEタイプかどうかを確認し、それ以外はエラーを返しています。追加の検証として、拡張子の確認や、画像処理ライブラリ(Pillowなど)での読み込みチェックも有効です。

🧰 応用:複数ファイルのアップロード

複数ファイルを一度にアップロードしたい場合は、List[UploadFile] を使います。これは、複数の画像や書類を一括で登録する機能を作る際に非常に便利です。

from typing import List

@app.post("/upload-multiple/")
async def upload_multiple(files: List[UploadFile] = File(...)):
    return {"filenames": [file.filename for file in files]}

HTML側のフォーム:

<form action="/upload-multiple/" enctype="multipart/form-data" method="post">
  <input name="files" type="file" multiple>
  <input type="submit">
</form>

このように multiple 属性を使用することで、ユーザーは複数ファイルを一度に選択してアップロードできます。サーバー側では、リストで受け取って各ファイルを個別に処理できます。

🎯 まとめ

  • FastAPIではUploadFileを用いることで効率的なファイルアップロードが可能です。非同期処理によりパフォーマンスにも優れています。
  • 画像ファイルなどの保存や形式チェック、セキュリティ対策もコードで明確に行うことができます。
  • 複数ファイルの一括処理も標準で対応しており、実践的なアプリケーション開発にも即応できます。

株式会社ONE WEDGE

【Serverlessで世の中をもっと楽しく】 ONE WEDGEはServerlessシステム開発を中核技術としてWeb系システム開発、AWS/GCPを利用した業務システム・サービス開発、PWAを用いたモバイル開発、Alexaスキル開発など、元気と技術力を武器にお客様に真摯に向き合う価値創造企業です。
https://onewedge.co.jp/

Discussion