目次
22 章

FastAPI のはじめ方とセットアップ

なぜ FastAPI なのか、uv で最初のプロジェクトをセットアップし、Hello FastAPI、OpenAPI/Swagger UI の自動生成までをまとめます。

4部 実戦 FastAPI の出発点です。1部 (入門) → 2部 (構造化) → 3部 (深さ・並行性) の 21 章が集まる舞台です。FastAPI で 1 つのプロジェクト を作りながら、型ヒント、dataclass / Pydantic、async / await、依存性注入、テストまで、これまで磨いた道具をまとめて使います。

4部の構成:

作るのは小さな TODO API — ユーザーの会員登録 / ログイン、TODO の CRUD、非同期タスクの処理、テスト、デプロイまでです。各章はその上に一段ずつ積み重なります。

なぜ FastAPI なのか #

Python の Web フレームワークはたくさんあります。Django、Flask、FastAPI、Litestar、Starlette など。それぞれに強みがあります。

DjangoFlaskFastAPI
スタイルフルスタック (バッテリー同梱)マイクロマイクロ + 型
非同期部分的 (4.0+)外部ライブラリネイティブ
型ヒント活用補助的補助的コア動作
自動ドキュメント (OpenAPI)別ライブラリビルトイン
学習曲線非常になだらかなだらか
データ検証DRF + 自前自前Pydantic 自動

FastAPI の強みは 型ヒントがそのまま動作する ことです。関数シグネチャを書くと、それが即:

  • 入力検証
  • シリアライズ / デシリアライズ
  • OpenAPI スキーマ (Swagger UI 自動生成)
  • エディタの自動補完
  • 静的型チェック

この 5 つが一度に起こります。他のフレームワークではそれぞれを別の設定で組まなければなりません。本書で磨いた型ヒントが最も活きるフレームワーク が FastAPI で、だから本書の収束点として選びました。

プロジェクトのセットアップ #

第1章 の uv の流れで始めます。

プロジェクトを作る
uv init todo-api --python 3.14
cd todo-api

依存関係のインストール #

実行に必要な依存関係
uv add "fastapi[standard]"

fastapi[standard] 一行に付いてくるもの:

  • FastAPI — フレームワーク本体
  • uvicorn — ASGI サーバー (開発 / プロダクション)
  • pydantic — データ検証
  • httpx — テスト用クライアント (第28章で)
  • email-validatorEmailStr 検証
  • python-multipart — フォーム / ファイルアップロード
  • fastapi-clifastapi CLI コマンド

次に開発用ツール。

開発ツール
uv add --dev pytest pytest-asyncio ruff pyright

第30章 型チェッカ設定と CI 統合 で本ツールたちの正式セットアップを扱います。FastAPI テストの標準は pytest + httpx の組み合わせです (第28章 テストとデプロイ で詳しく)。

最初のエンドポイント #

app/main.py
from fastapi import FastAPI

app = FastAPI(
    title="Todo API",
    version="0.1.0",
    description="モダン Python 書籍のサンプル API",
)

@app.get("/")
def read_root() -> dict[str, str]:
    return {"hello": "fastapi"}

これで終わりです。7 行の Python で HTTP サーバーになります。

実行 #

開発モード
uv run fastapi dev app/main.py

fastapi dev がやること:

  • uvicorn を立ち上げ
  • コード変更時に自動リロード
  • デバッグログ
  • LAN 公開しない (127.0.0.1 だけ)

ブラウザで http://127.0.0.1:8000 を開くと:

{"hello": "fastapi"}

より重要なもの — 自動ドキュメント #

同じサーバーの /docs に行ってみてください。Swagger UI が自動で立ち上がっています。エンドポイント一覧、入力スキーマ、レスポンスモデル、そのまま呼び出せる「Try it out」 ボタンまで。コードを 1 行も追加していないのに。

/redoc に行くと ReDoc スタイルのドキュメントもあります。

これが FastAPI の言う 自動ドキュメント の正体です。関数シグネチャ + 型ヒント + docstring がそのまま OpenAPI 仕様に変換されます。

より豊かなエンドポイント #

複数のメソッド / パス
from fastapi import FastAPI

app = FastAPI(title="Todo API", version="0.1.0")

@app.get("/")
def read_root() -> dict[str, str]:
    """ルート — ヘルスチェック用。"""
    return {"hello": "fastapi"}

@app.get("/items/{item_id}")
def read_item(item_id: int) -> dict[str, int]:
    """ID で単一アイテムを取得。"""
    return {"item_id": item_id}

@app.get("/items")
def list_items(skip: int = 0, limit: int = 10) -> dict[str, int]:
    """ページネーションのクエリパラメータ。"""
    return {"skip": skip, "limit": limit}

ここで起こる自動変換:

  • パスパラメータ {item_id} → 関数の引数 item_id: int
    • int でなければ 422 Unprocessable Entity が自動で返る
  • クエリパラメータ skiplimit → デフォルト値ありの関数引数
    • ?skip=10&limit=20 の形で自動パース
  • 戻り値の型 -> dict[str, int] → JSON レスポンス
  • docstring → Swagger UI の説明

int 型を書いただけで自動で変換・検証が行われるのが核心です。Flask なら:

🚫 Flask との比較
@app.route("/items/<int:item_id>")
def read_item(item_id):
    return jsonify({"item_id": item_id})

<int:item_id> のようにルーターに型を書き、検証失敗のレスポンスを自分で処理しなければなりません。FastAPI は 関数シグネチャがルーター仕様 です。

PathQuery — より細かい検証 #

高度な検証
from fastapi import FastAPI, Path, Query
from typing import Annotated

app = FastAPI()

@app.get("/items/{item_id}")
def read_item(
    item_id: Annotated[int, Path(ge=1, le=10000, description="アイテム ID")],
    q: Annotated[str | None, Query(min_length=3, max_length=50)] = None,
):
    return {"item_id": item_id, "q": q}

Path()Query()検証ルールメタデータ を追加します。

  • ge=1>= 1
  • le=10000<= 10000
  • min_length=3 — 最小 3 文字
  • description=... — Swagger ドキュメントに表示

Annotated[T, ...] のパターンが第20章 typing 高度 で見たそれです — 型にメタデータを束ねる標準。FastAPI のほとんどすべての依存性注入がこのパターンの上に作られています。

レスポンス — 自動シリアライズ #

dataclass / Pydantic モデルを返す
from datetime import datetime, timezone
from pydantic import BaseModel

class Todo(BaseModel):
    id: int
    title: str
    done: bool
    created_at: datetime

@app.get("/todos/1")
def get_todo() -> Todo:
    return Todo(
        id=1,
        title="FastAPI 学習",
        done=False,
        created_at=datetime.now(timezone.utc),
    )

レスポンス:

{
  "id": 1,
  "title": "FastAPI 学習",
  "done": false,
  "created_at": "2026-05-01T12:00:00+00:00"
}

datetime のような非 JSON 型も 自動変換 されます。Pydantic がシリアライズを担当します。これを自前で書くとルートごとに変換コードを書かなければなりませんが、FastAPI は戻り値の型を書くだけ。

Todo モデルの詳細は第23章 ルーティング、Pydantic モデル、依存性注入 と第24章 Pydantic v2 の深層 で。

エラー — HTTPException #

エラーレスポンス
from fastapi import HTTPException

todos: dict[int, Todo] = {1: Todo(...)}

@app.get("/todos/{todo_id}")
def get_todo(todo_id: int) -> Todo:
    if todo_id not in todos:
        raise HTTPException(status_code=404, detail="Todo not found")
    return todos[todo_id]

raise HTTPException(...) 一行で JSON エラーレスポンス が返ります。

{"detail": "Todo not found"}

標準の HTTP ステータスコード (404、400、500 など) と一緒に。4部を進めながらユーザー定義の例外ハンドラも扱います。

プロジェクト構造 — 最初から整理する #

小さな API でも最初から モジュール / パッケージ に分けると、第7章 モジュール、パッケージと pyproject.toml で見た流れがそのまま生きます。

基本構造 (4部が埋めていく形)
todo-api/
├── pyproject.toml
├── app/
│   ├── __init__.py
│   ├── main.py            # FastAPI インスタンス、ルーター登録
│   ├── core/
│   │   ├── config.py      # 環境変数
│   │   └── security.py    # JWT、パスワード (第26章)
│   ├── api/
│   │   ├── __init__.py
│   │   ├── deps.py        # 依存性注入 (第23、26章)
│   │   ├── todos.py       # TODO ルーター
│   │   └── auth.py        # 認証ルーター (第26章)
│   ├── models/            # SQLAlchemy モデル (第25章)
│   │   └── todo.py
│   ├── schemas/           # Pydantic スキーマ (第23、24章)
│   │   └── todo.py
│   └── db/                # DB 接続 (第25章)
│       └── session.py
├── alembic/               # マイグレーション (第25章)
└── tests/                 # pytest (第28章)
    └── test_todos.py

本章では app/main.py 一ファイルですが、次の章から一つずつディレクトリを構成していきます。第29章 総合実習 — TODO API を完成させる で全体の形がそろいます。

環境変数 — pydantic-settings #

設定値 (DB URL、JWT シークレットなど) をコードに埋め込まず、環境変数に分離するのが標準です。FastAPI 陣営の標準ツールは pydantic-settings

インストール
uv add pydantic-settings
app/core/config.py
from pydantic_settings import BaseSettings, SettingsConfigDict

class Settings(BaseSettings):
    app_name: str = "Todo API"
    database_url: str = "sqlite+aiosqlite:///./todo.db"
    jwt_secret: str = "dev-only-change-me"
    jwt_expire_minutes: int = 60

    model_config = SettingsConfigDict(env_file=".env", env_file_encoding="utf-8")

settings = Settings()

.env ファイルから自動で読み、環境変数があればそれで上書きします。型検証まで 含むので、誤った環境変数は起動時点で止まります。

.env
JWT_SECRET=production-secret-here
DATABASE_URL=postgresql+asyncpg://user:pw@localhost/todo

.env は git から除外 (.gitignore に追加)。セキュリティに注意 — 第31章 logging と観測性 で secret ロギング防止も扱います。

急いでまとめた最初の章の成果物 #

app/main.py — 本章の仕上げ
from fastapi import FastAPI, HTTPException
from app.core.config import settings

app = FastAPI(
    title=settings.app_name,
    version="0.1.0",
)

@app.get("/")
def read_root() -> dict[str, str]:
    return {"app": settings.app_name, "status": "ok"}

@app.get("/health")
def health() -> dict[str, str]:
    return {"status": "healthy"}
実行
uv run fastapi dev app/main.py
# → http://127.0.0.1:8000
# → http://127.0.0.1:8000/docs

エンドポイント 2 つ + 自動ドキュメント + 環境変数の分離。次の章の出発点です。

練習問題 #

  1. uv init todo-api --python 3.14 でプロジェクトを作り、fastapi[standard] を追加してください。app/main.pyGET /GET /items/{item_id}GET /items?skip&limit の 3 つのエンドポイントを書き、fastapi dev で立ち上げた後、/docs で Swagger UI が自動生成されるかを確認します。
  2. Annotated[int, Path(ge=1, le=100)]item_id に範囲検証を追加してください。範囲外の ID で呼び出すと自動で 422 レスポンスが返るかを確認します。Swagger UI の入力フォームに検証ルールが表示されるかも確認します。
  3. pydantic-settingsapp/core/config.py を書き、.env から app_name / database_url を読むようにします。環境変数が誤った型 (例: database_url に空文字列) のとき、起動時点でエラーが出るかを確認します。

一行まとめ: FastAPI の強みは型ヒントが検証 / シリアライズ / ドキュメント / 自動補完にそのまま動作。uv add "fastapi[standard]" 一行で uvicorn / pydantic / httpx すべて付いてくる。fastapi dev で自動リロード。関数シグネチャがルーター仕様、/docs に Swagger 自動。Annotated[T, Path(...)] / Annotated[T, Query(...)] で検証強化、Pydantic モデル返却時に datetime などを自動シリアライズ、HTTPException でエラー、pydantic-settings で環境変数分離、最初からモジュール / パッケージ構造。

次の章 #

次の 第23章 ルーティング、Pydantic モデル、依存性注入 では APIRouter でルートを分離し、Pydantic スキーマ を本格的に使い、依存性注入 でルート間の共通ロジック (認証済みユーザー、DB セッションなど) を分離するパターンを扱います。

X