FastAPI のはじめ方とセットアップ
なぜ FastAPI なのか、uv で最初のプロジェクトをセットアップし、Hello FastAPI、OpenAPI/Swagger UI の自動生成までをまとめます。
4部 実戦 FastAPI の出発点です。1部 (入門) → 2部 (構造化) → 3部 (深さ・並行性) の 21 章が集まる舞台です。FastAPI で 1 つのプロジェクト を作りながら、型ヒント、dataclass / Pydantic、async / await、依存性注入、テストまで、これまで磨いた道具をまとめて使います。
4部の構成:
- 第22章 はじめ方とセットアップ、OpenAPI ← 本章
- 第23章 ルーティング、Pydantic モデル、依存性注入
- 第24章 Pydantic v2 の深層 ★新規
- 第25章 DB 連携 — SQLAlchemy 2.x + Alembic
- 第26章 認証 — OAuth2 パスワードフロー + JWT
- 第27章 非同期とバックグラウンドジョブ
- 第28章 テストとデプロイ — pytest、Docker、Railway/Fly
- 第29章 総合実習 — TODO API を完成させる ★新規
作るのは小さな TODO API — ユーザーの会員登録 / ログイン、TODO の CRUD、非同期タスクの処理、テスト、デプロイまでです。各章はその上に一段ずつ積み重なります。
なぜ FastAPI なのか #
Python の Web フレームワークはたくさんあります。Django、Flask、FastAPI、Litestar、Starlette など。それぞれに強みがあります。
| Django | Flask | FastAPI | |
|---|---|---|---|
| スタイル | フルスタック (バッテリー同梱) | マイクロ | マイクロ + 型 |
| 非同期 | 部分的 (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-validator —
EmailStr検証 - python-multipart — フォーム / ファイルアップロード
- fastapi-cli —
fastapiCLI コマンド
次に開発用ツール。
uv add --dev pytest pytest-asyncio ruff pyright第30章 型チェッカ設定と CI 統合 で本ツールたちの正式セットアップを扱います。FastAPI テストの標準は pytest + httpx の組み合わせです (第28章 テストとデプロイ で詳しく)。
最初のエンドポイント #
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.pyfastapi 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: intintでなければ 422 Unprocessable Entity が自動で返る
- クエリパラメータ
skip、limit→ デフォルト値ありの関数引数?skip=10&limit=20の形で自動パース
- 戻り値の型
-> dict[str, int]→ JSON レスポンス - docstring → Swagger UI の説明
int 型を書いただけで自動で変換・検証が行われるのが核心です。Flask なら:
@app.route("/items/<int:item_id>")
def read_item(item_id):
return jsonify({"item_id": item_id})<int:item_id> のようにルーターに型を書き、検証失敗のレスポンスを自分で処理しなければなりません。FastAPI は 関数シグネチャがルーター仕様 です。
Path、Query — より細かい検証
#
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—>= 1le=10000—<= 10000min_length=3— 最小 3 文字description=...— Swagger ドキュメントに表示
Annotated[T, ...] のパターンが第20章 typing 高度 で見たそれです — 型にメタデータを束ねる標準。FastAPI のほとんどすべての依存性注入がこのパターンの上に作られています。
レスポンス — 自動シリアライズ #
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 で見た流れがそのまま生きます。
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-settingsfrom 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 ファイルから自動で読み、環境変数があればそれで上書きします。型検証まで 含むので、誤った環境変数は起動時点で止まります。
JWT_SECRET=production-secret-here
DATABASE_URL=postgresql+asyncpg://user:pw@localhost/todo.env は git から除外 (.gitignore に追加)。セキュリティに注意 — 第31章 logging と観測性 で secret ロギング防止も扱います。
急いでまとめた最初の章の成果物 #
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 つ + 自動ドキュメント + 環境変数の分離。次の章の出発点です。
練習問題 #
uv init todo-api --python 3.14でプロジェクトを作り、fastapi[standard]を追加してください。app/main.pyにGET /、GET /items/{item_id}、GET /items?skip&limitの 3 つのエンドポイントを書き、fastapi devで立ち上げた後、/docsで Swagger UI が自動生成されるかを確認します。Annotated[int, Path(ge=1, le=100)]でitem_idに範囲検証を追加してください。範囲外の ID で呼び出すと自動で 422 レスポンスが返るかを確認します。Swagger UI の入力フォームに検証ルールが表示されるかも確認します。pydantic-settingsでapp/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 セッションなど) を分離するパターンを扱います。