FastAPIによるWebアプリケーション構築

FastAPIはPythonのモダンなWebフレームワークで、ASGIベースの非同期処理をネイティブにサポートすることで、従来のWSGIベースフレームワークと比較して優れたパフォーマンスを実現します。Python 3.6以上の環境が必要です。

環境構築と最小構成

必要なパッケージをインストールします。

pip install fastapi
pip install uvicorn[standard]

シンプルなAPIサーバを構築する例です。

from fastapi import FastAPI

server = FastAPI()

@server.get("/api/status")
def health_check():
    return {"status": "operational", "version": "1.0.0"}

if __name__ == "__main__":
    import uvicorn
    uvicorn.run(server, host="0.0.0.0", port=8000)

Jinja2テンプレート統合

FastAPIはテンプレートエンジンを内包していないため、Starletteの機能を利用してJinja2を統合します。

from fastapi import FastAPI
from fastapi.requests import Request
from fastapi.templating import Jinja2Templates

server = FastAPI()
renderer = Jinja2Templates(directory="templates")

@server.get("/")
async def render_index(request: Request):
    return renderer.TemplateResponse(
        "dashboard.html",
        {
            "request": request,
            "page_title": "管理画面",
            "user_count": 42
        }
    )

@server.get("/item/{identifier}")
async def render_detail(request: Request, identifier: str):
    return renderer.TemplateResponse(
        "detail.html",
        {
            "request": request,
            "item_id": identifier,
            "timestamp": "2024-01-15"
        }
    )

フォームデータの処理

標準フォームフィールド

from fastapi import FastAPI, Form
from fastapi.requests import Request
from fastapi.templating import Jinja2Templates

server = FastAPI()
renderer = Jinja2Templates(directory="templates")

@server.get("/login")
async def show_login_form(request: Request):
    return renderer.TemplateResponse("login.html", {"request": request})

@server.post("/authenticate")
async def process_login(
    request: Request,
    email: str = Form(...),
    password: str = Form(...),
    remember: bool = Form(default=False)
):
    return renderer.TemplateResponse(
        "result.html",
        {
            "request": request,
            "credential": email,
            "persistent": remember
        }
    )

ファイルアップロード

from fastapi import FastAPI, File, UploadFile, Form
from fastapi.requests import Request
from fastapi.templating import Jinja2Templates
from typing import Sequence

server = FastAPI()
renderer = Jinja2Templates(directory="templates")

@server.get("/upload")
async def show_upload_interface(request: Request):
    return renderer.TemplateResponse("upload.html", {"request": request})

@server.post("/single-upload")
async def handle_single_file(
    request: Request,
    raw_bytes: bytes = File(...),
    metadata: UploadFile = File(...),
    description: str = Form(...)
):
    return renderer.TemplateResponse(
        "upload_result.html",
        {
            "request": request,
            "byte_length": len(raw_bytes),
            "original_name": metadata.filename,
            "mime_type": metadata.content_type,
            "caption": description
        }
    )

@server.post("/multi-upload")
async def handle_multiple_files(
    request: Request,
    binary_collection: Sequence[bytes] = File(...),
    file_objects: Sequence[UploadFile] = File(...)
):
    return renderer.TemplateResponse(
        "batch_result.html",
        {
            "request": request,
            "size_list": [len(data) for data in binary_collection],
            "name_list": [obj.filename for obj in file_objects]
        }
    )

静的ファイルの提供

CSS、JavaScript、画像などの静的ファイルを配信する設定です。

from fastapi import FastAPI
from fastapi.staticfiles import StaticFiles

server = FastAPI()

server.mount("/assets", StaticFiles(directory="static"), name="resources")

テンプレート内での参照方法:

<link rel="stylesheet" href="{{ url_for('resources', path='/styles/main.css') }}">
<img src="{{ url_for('resources', path='/images/logo.png') }}" alt="ロゴ">
<script src="{{ url_for('resources', path='/scripts/app.js') }}"></script>

タグ: fastapi asgi Jinja2 uvicorn starlette

8月13日 22:25 投稿