FastAPI + MySQL + Alembicでアプリ開発をしよう

## はじめに
本記事では、仮想環境を使用してローカルで FastAPI + MySQL + Alembic 環境を構築し、Todoアプリを開発しながら、マイグレーションの流れを実践的に学びます。
ハッカソンや短期開発プロジェクトでは、迅速に開発環境を構築し、チーム全体で一貫性のある構成を保つことが求められます。特にデータベースを扱うアプリケーションでは、テーブル設計の変更（スキーマの変更管理）は避けられません。こうしたスキーマ変更を安全かつ確実に管理・反映していくには、マイグレーションの仕組みが不可欠です。FastAPIは軽量で柔軟な設計を持つ一方、Djangoのようにマイグレーション機能が内蔵されていないため、Alembicによる明示的な設定と運用が求められます。
FastAPIが初めての方や「マイグレーションって何？」という方にも理解しやすいよう、実践的かつ段階的に構成しています。

## 前提条件
- OS：Windows または macOS / Linux
- Python： vesrion 3.10以上

## ディレクトリ構成
プロジェクトのディレクトリ構造は以下の構成です：

```

fastapi_todo/
├── migrations/                       # Alembicのマイグレーション用ディレクトリ
│   ├── versions/                     # 自動生成されるマイグレーションスクリプト格納場所
│   ├── env.py                        # マイグレーション実行時の設定ファイル
│   └── script.py.mako                # マイグレーションファイルのテンプレート
│
├── app/                              # アプリケーション本体
│   ├── __init__.py                   # パッケージとして認識させるための初期化ファイル
│   ├── main.py                       # FastAPIのエントリーポイント
│   ├── database.py                   # SQLAlchemyエンジンとセッション管理
│   ├── models.py                     # SQLAlchemy ORMモデル定義
│   ├── schemas.py                    # Pydanticスキーマ（入力/出力の型定義）
│   └── crud.py                       # DBに関する操作を記述するCRUD処理
│
├── .env                              # DB URLや認証情報などの環境変数
├── .gitignore                        # Gitで追跡しないファイル/ディレクトリを指定
├── alembic.ini                       # Alembic全体の設定ファイル
├── requirements.txt                  # インストールパッケージ一覧
└── venv/                             # Python仮想環境（自動生成）

```
## 仮想環境のセットアップ

### 1. プロジェクトディレクトリを作成し、移動する
```
mkdir fastapi-todo
cd fastapi-todo
```

### 2\. 仮想環境を作成する
```
python3 -m venv venv
```

### 3\. 仮想環境を有効化する

- Linux/macOSの場合

```
source venv/bin/activate
```

- Windowsの場合

```
venv\Scripts\activate
```

仮想環境が有効化されると、コマンドプロンプトの先頭に (venv) と表示されます：
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3958955/16fd9cbc-3f19-4923-b70e-3797b98e36ff.png)

## MySQLをセットアップする
FastAPI + SQLAlchemy でアプリケーションを開発するには、MySQL をローカルにインストールし、適切なユーザー・データベースを作成しておく必要があります。ここでは MySQL のインストールから、ユーザー作成、接続確認までの流れを紹介します。

### 1. MySQLをインストールする

- Linuxの場合

```bash
sudo apt update
sudo apt install mysql-server -y
```

- macOSの場合
```bash
brew update
brew install mysql
brew services start mysql
```

- Windowsの場合
MySQL公式サイトからWindowsインストーラーをダウンロードしてインストールして
ください。
※「MySQL Server」と「MySQL Workbench」の両方を選択してOKです。インストーラー内で自動起動設定がされます。

https://dev.mysql.com/downloads/installer/

### 2\. MySQL の初期設定を行う
Linuxでは次のコマンドで初期設定ウィザードを起動できます：

```
sudo mysql_secure_installation
```

rootパスワードの設定や匿名ユーザーの削除、リモートログインの無効化などの設定を求められますが、「**Y**」を選択して問題ありません。


### 3\. バージョンを確認する

```
mysql --version
```
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3958955/938e950a-7013-4653-ada2-2a1b2c559a5c.png)

### 4\. MySQL を起動する（Linux）

```
sudo systemctl enable mysql
sudo service mysql start
```

以下のコマンドで、起動状態を確認することができます。
`mysql` サービスが `active (running)` であれば、起動成功です：

```
sudo service mysql status
```
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3958955/b1530c8f-a55a-4748-bc97-d75312daac7f.png)

### 5\. rootユーザーでログインできるかを確認する
パスワードはインストール時または初期設定で決めたものを使用してください。
```
mysql -u root -p
```

 `mysql>`（MySQLプロンプト）が作成されたら、ログイン成功です。

### 6\. アプリケーション用のユーザー・DB を作成する
この後に設定する `.env` ファイルの接続情報に合わせて、MySQLにアプリケーション専用のデータベースとユーザーを作成しておきます。  これにより、rootユーザーを使わずに、アプリケーションから安全にデータベースへアクセスできるようになります。

 MySQL クライアントを起動した状態で以下を実行します：

 ```bash
# アプリケーション用のデータベースを作成
CREATE DATABASE fastapi_todo;
# アプリケーション専用のユーザーを作成
CREATE USER 'fastapi_user'@'localhost' IDENTIFIED BY 'fastapi_pass';
# 作成したユーザーにデータベースの権限を付与
GRANT ALL PRIVILEGES ON fastapi_todo.* TO 'fastapi_user'@'localhost';
# 権限変更を反映
FLUSH PRIVILEGES;
 ```
 MySQL クライアントを終了するには、 `exit; ` または ` quit; ` と入力します。

これらのコマンドを実行することで、以下の設定が完了します：
- 「fastapi_todo」というデータベースを作成
- アプリケーション用のユーザー「fastapi_user」を作成
- ユーザー「fastapi_user」に「fastapi_todo」データベースへの全権限を付与

### 7\.  データベースの存在を確認する
 ```
SHOW DATABASES;
```


## 環境設定ファイルの作成を作成する（.env）
データベース接続情報などを管理するための .env ファイルを作成します。これにより、接続情報をソースコードから分離し、安全に管理できます。

以下は `.env` ファイルの例です。実際の開発では、適切な値に置き換えてください：

```bash
# MySQLの接続情報
MYSQL_ROOT_PASSWORD=your_root_password
MYSQL_DATABASE=fastapi_todo
MYSQL_USER=your_db_user
MYSQL_PASSWORD=your_db_password

# SQLAlchemy用の接続URL
DATABASE_URL=mysql+pymysql://your_db_user@localhost:3306/fastapi_todo
```

## 依存ライブラリのインストール（requirements.txt）

### 1. requirements.txt を作成する
まず最初に、必要なライブラリをインストールするために requirements.txt を作成します。

以下をコピーして作成してください：

```requirements.txt
fastapi==0.110.0
sqlalchemy==2.0.29
alembic==1.13.1
pymysql==1.1.0
uvicorn[standard]==0.29.0
python-dotenv==1.0.1
cryptography==42.0.5
```

### ライブラリの説明
- fastapi
    - Python製の高速なWeb APIフレームワーク
- sqlalchemy
    - PythonからSQL（MySQLなど）を安全に扱うためのORM
- alembic
    - テーブル構造の変更履歴を管理するSQLAlchemy用のマイグレーションツール
- pymysql
    - SQLAlchemyからMySQLへ接続するために使うMySQLとPythonをつなぐドライバー
- uvicorn[standard]	
    - FastAPIアプリを起動するためのASGIサーバー
※[standard]を付けることでログや再起動機能も有効
- python-dotenv		
    - .envファイルから環境変数を読み込むためのライブラリ

### インストール
以下のコマンドで、requirements.txt に記載されたすべてのライブラリを一括インストールします：

```
pip install -r requirements.txt
```

### 確認

以下のコマンドを実行します：

```
pip list
```

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3958955/85000ed5-ec7f-4c86-ac31-959038f35d93.png)

ライブラリ一覧に `fastapi` や `sqlalchemy` など、requirements.txtに記載したライブラリが
表示されていればインストールは成功です。

※画像は一部のライブラリのみを抜粋しています。

## .gitignore ファイルを作成する
プロジェクトを Git で管理する場合は、追跡しないファイルやディレクトリを指定するための .gitignore ファイルを作成します。

```.gitignore
# 環境変数ファイル（機密情報を含むため）
.env

# Python 仮想環境
venv/
__pycache__/
*.py[cod]
*$py.class
*.so
.Python
env/
build/
develop-eggs/
dist/
downloads/
eggs/
.eggs/
lib/
lib64/
parts/
sdist/
var/
*.egg-info/
.installed.cfg
*.egg

# IDE関連ファイル
.idea/
.vscode/
*.swp
*.swo

# ログファイル
*.log

# ローカル設定ファイル
local_settings.py

# データベースファイル
*.sqlite3
*.db
```

## アプリケーションの基本構造を作成する

### 1. app ディレクトリの作成する
app ディレクトリをパッケージとして認識させるために、空の __init__.py ファイルを作成します。

 ```bash
 mkdir -p app
```

### 2\. init.py ファイルを作成する

- Linux/macOSの場合

```
touch app/__init__.py
```

- Windowsの場合

```
type nul > app\__init__.py
```
 
### 3\. データベース接続設定を行う（app/database.py）
database.pyは、アプリケーションとデータベースの橋渡しをするためのファイルです。アプリケーション全体のデータアクセスが一貫したほうオフで管理され、安全で効率的なデータベース操作が可能になります。

主な役割：
- 環境変数（.env）からデータベース接続情報を読み込む
    - 開発・テスト・本番環境で同じコードを使いながら、データベース設定だけを .env で 切り替えることができる
- SQLAlchemyのエンジンとセッション管理を設定する
    - リクエスト処理中だけデータベース接続を維持し、終了後は自動的に接続を閉じることで
- データベースセッションを管理する関数を提供する
    - 複数のテーブル更新を一つのトランザクションとして扱い、処理の整合性を保証する
    
 ```app/database.py
from sqlalchemy import create_engine
from sqlalchemy.ext.declarative import declarative_base
from sqlalchemy.orm import sessionmaker
from dotenv import load_dotenv
import os

# .envファイルから環境変数を読み込む
load_dotenv()

# データベースURLを取得
DATABASE_URL = os.getenv("DATABASE_URL")

# SQLAlchemyのエンジンを作成
engine = create_engine(DATABASE_URL)

# セッションクラスを作成
SessionLocal = sessionmaker(autocommit=False, autoflush=False, bind=engine)

# モデルのBaseクラスを作成
Base = declarative_base()

# DBセッションを取得するための関数を定義
def get_db():
    db = SessionLocal()
    try:
        yield db
    finally:
        db.close()
 ```

### 3\. データベースモデルを定義する（app/models.py）
models.pyはデータベースのテーブル構造をPythonクラスとして定義します。

主な役割：
- データとコードの橋渡し 
    - データベースのテーブルと列を Python のクラスとプロパティとして表現し、SQLを直接書かずにPythonでデータ操作ができる
- 型の安全性
    - 各カラムの型（文字列、数値、日時など）を明示的に定義することで、型の不一致によるエラーを防ぐ
- 自動処理の活用
    - 複数のテーブル更新を一つのトランザクションとして扱い、処理の整合性を保証する
- テーブル間の関係定義
    - 実際のアプリでは複数テーブル間のリレーションシップを定義できる

本アプリの Todoクラスでは、タスク管理に必要なタイトルや説明、完了状態などの基本情報と、作成・更新日時を自動記録する仕組みを定義しています。このモデル定義があることで、データベース操作をSQLではなくPythonオブジェクトとして扱えるようになります。

 ```app/models.py
from sqlalchemy import Column, Integer, String, Boolean, DateTime
from sqlalchemy.sql import func
from .database import Base

class Todo(Base):
    __tablename__ = "todos"
    
    id = Column(Integer, primary_key=True, index=True)
    title = Column(String(100), nullable=False)
    description = Column(String(255))
    completed = Column(Boolean, default=False)
    created_at = Column(DateTime(timezone=True), server_default=func.now())
    updated_at = Column(DateTime(timezone=True), onupdate=func.now())
 ```

### 4\. Pydantic スキーマを定義する（app/schemas.py）
schemas.pyでは、APIのリクエストやレスポンスでやり取りするデータ構造（スキーマ）を Pydantic の `BaseModel` を使って定義します。

主な役割：
- データの検証
    - リクエスト時に送られるデータが正しい形式かどうかを自動的にチェックする
- データの変換
    - 受け取った JSON データを Python オブジェクトに変換、逆にレスポンスでは Python オブジェクトを JSON に変換する
- 自動ドキュメント生成
    - FastAPI は Pydantic モデルをもとに Swagger UI（/docs）を自動生成するため、スキーマ定義がそのままAPIドキュメントになる

```app/schemas.py
from pydantic import BaseModel
from datetime import datetime
from typing import Optional

# Todoの作成時に使用するスキーマ
class TodoCreate(BaseModel):
    title: str
    description: Optional[str] = None
    completed: Optional[bool] = False

# Todoの更新時に使用するスキーマ
class TodoUpdate(BaseModel):
    title: Optional[str] = None
    description: Optional[str] = None
    completed: Optional[bool] = None

# Todoの読み取り時に使用するスキーマ
class TodoResponse(BaseModel):
    id: int
    title: str
    description: Optional[str] = None
    completed: bool
    created_at: datetime
    updated_at: Optional[datetime] = None
    
    class Config:
        orm_mode = True
```

### 5\. CRUD 操作を実装する（app/crud.py）
crud.pyは、データベースにおけるCRUD 操作を行うための関数をまとめたモジュールです。

主な役割：
- ビジネスロジック（APIエンドポイント）とデータアクセスを分離
    - データベースのテーブルと列を Python のクラスとプロパティとして表現し、SQLを直接書かずにPythonでデータ操作ができる
- データベース操作を再利用可能な関数として提供
    - 各カラムの型（文字列、数値、日時など）を明示的に定義することで、型の不一致によるエラーを防ぐ
- モデルとスキーマ間のデータ変換を処理
 
- エラーハンドリングとデータ整合性の確保
    - 実際のアプリでは複数テーブル間のリレーションシップを定義できる

実際には、Todo アプリのタスクに対する作成、読み取り、更新、削除のすべての操作を、SQLAlchemy を使って Python 関数として実装します。これにより API エンドポイントからは、SQL を直接書かずに、これらの関数を呼び出すだけでデータベース操作を行うことができます。
 
```app/crud.py
from sqlalchemy.orm import Session
from typing import List, Optional
from . import models, schemas

# タスク一覧を取得
def get_todos(db: Session, skip: int = 0, limit: int = 100) -> List[models.Todo]:
    return db.query(models.Todo).offset(skip).limit(limit).all()

# IDを指定して単一のタスクを取得
def get_todo(db: Session, todo_id: int) -> Optional[models.Todo]:
    return db.query(models.Todo).filter(models.Todo.id == todo_id).first()

# 新しいタスクをデータベースに追加
def create_todo(db: Session, todo: schemas.TodoCreate) -> models.Todo:
    db_todo = models.Todo(**todo.dict())
    db.add(db_todo)
    db.commit()
    db.refresh(db_todo)
    return db_todo

#  既存タスクの情報を更新
def update_todo(db: Session, todo_id: int, todo: schemas.TodoUpdate) -> Optional[models.Todo]:
    db_todo = get_todo(db, todo_id)
    if db_todo:
        update_data = todo.dict(exclude_unset=True)
        for key, value in update_data.items():
            setattr(db_todo, key, value)
        db.commit()
        db.refresh(db_todo)
    return db_todo

# タスクをデータベースから削除
def delete_todo(db: Session, todo_id: int) -> bool:
    db_todo = get_todo(db, todo_id)
    if db_todo:
        db.delete(db_todo)
        db.commit()
        return True
    return False
```

### 6\. FastAPI アプリケーション実装（app/main.py）
main.pyは、FastAPIアプリケーションのメインエントリーポイントを定義するファイルです。APIのエンドポイントを定義し、リクエストとレスポンスの処理を行います。

```app/main.py
from fastapi import FastAPI, Depends, HTTPException
from sqlalchemy.orm import Session
from typing import List

from . import crud, models, schemas
from .database import engine, get_db

# FastAPIアプリケーションのインスタンスを作成
app = FastAPI(title="FastAPI Todo App")

# ルートエンドポイント
@app.get("/")
def read_root():
    return {"message": "Welcome to Todo API"}

# タスク一覧の取得エンドポイント
@app.get("/todos/", response_model=List[schemas.TodoResponse])
def read_todos(skip: int = 0, limit: int = 100, db: Session = Depends(get_db)):
    # CRUDモジュールのget_todos関数を呼び出し
    todos = crud.get_todos(db, skip=skip, limit=limit)
    return todos

# 特定のタスクを取得するエンドポイント
@app.get("/todos/{todo_id}", response_model=schemas.TodoResponse)
def read_todo(todo_id: int, db: Session = Depends(get_db)):
    # CRUDモジュールのget_todo関数を呼び出し
    db_todo = crud.get_todo(db, todo_id=todo_id)
    if db_todo is None:
        # 見つからない場合は404エラー
        raise HTTPException(status_code=404, detail="Todo not found")
    return db_todo

# 新しいタスクを作成するエンドポイント
@app.post("/todos/", response_model=schemas.TodoResponse)
def create_todo(todo: schemas.TodoCreate, db: Session = Depends(get_db)):
    # CRUDモジュールのcreate_todo関数を呼び出し
    return crud.create_todo(db=db, todo=todo)

# タスクを更新するエンドポイント
@app.put("/todos/{todo_id}", response_model=schemas.TodoResponse)
def update_todo(todo_id: int, todo: schemas.TodoUpdate, db: Session = Depends(get_db)):
    # CRUDモジュールのupdate_todo関数を呼び出し
    db_todo = crud.update_todo(db=db, todo_id=todo_id, todo=todo)
    if db_todo is None:
        # 見つからない場合は404エラー
        raise HTTPException(status_code=404, detail="Todo not found")
    return db_todo

# タスクを削除するエンドポイント
@app.delete("/todos/{todo_id}")
def delete_todo(todo_id: int, db: Session = Depends(get_db)):
    # CRUDモジュールのdelete_todo関数を呼び出し
    success = crud.delete_todo(db=db, todo_id=todo_id)
    if not success:
        # 見つからない場合は404エラー
        raise HTTPException(status_code=404, detail="Todo not found")
    return {"message": "Todo deleted successfully"}
```

## Alembicによるマイグレーション環境の構築

### 1. Alembic の初期化を実施する

以下のコマンドを実行すると、指定した名前でディレクトリが作成され、
その中に Alembic の設定ファイルやスクリプトテンプレートが生成されます：

```bash
alembic init <作成するディレクトリ名>
```

実行すると、以下のようなディレクトリ構成になります：
※alembic.ini はルートディレクトリに作成されます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3958955/0e7a24dd-ac6b-4f51-968d-28c59b35967c.png)


### 2\. alembic.ini の設定
Alembic の初期設定ファイルである` alembic.ini `には、デフォルトで以下のような接続情報のテンプレートが記載されています：

```alembic.ini
sqlalchemy.url = driver://user:pass@localhost/dbname
```

本来はこの行に接続情報を記述しますが、接続情報を .env ファイルで一元管理するため、この行は編集せず、コメントアウトしておきます。接続情報の読み込みは後ほど` migrations/env.py `ファイル内で行うように変更します。

### 3\. env.pyの設定
Alembic が `.env`ファイルに記載されたデータベース接続情報（`DATABASE_URL` ）を
正しく読み込み、マイグレーションを実行できるように `migrations/env.py` を編集します。

```migrations/env.py 
from logging.config import fileConfig
import os # 追加
import sys # 追加

from sqlalchemy import engine_from_config
from sqlalchemy import pool

from alembic import context
from dotenv import load_dotenv # 追加

# this is the Alembic Config object, which provides
# access to the values within the .ini file in use.
config = context.config

# 環境変数の読み込みとDB接続設定を追加
load_dotenv()
database_url = os.getenv("DATABASE_URL")
if database_url is None:
    raise ValueError("DATABASE_URLの環境変数が見つかりません。")
config.set_main_option("sqlalchemy.url", database_url)

# Interpret the config file for Python logging.
# This line sets up loggers basically.
if config.config_file_name is not None:
    fileConfig(config.config_file_name)

# add your model's MetaData object here
# for 'autogenerate' support
# from myapp import mymodel
# target_metadata = mymodel.Base.metadata

# Alembic実行時にappディレクトリを Python のモジュール検索パスに追加
sys.path.append(os.path.join(os.path.dirname(__file__), '..')) 

from app.database import Base # Baseを取得するために追加
from app import models # モデル全体を読み込むために追加

target_metadata = Base.metadata # None → Base.metadataに変更

# other values from the config, defined by the needs of env.py,
# can be acquired:
# my_important_option = config.get_main_option("my_important_option")
# ... etc.

def run_migrations_offline() -> None:
    """Run migrations in 'offline' mode.

    This configures the context with just a URL
    and not an Engine, though an Engine is acceptable
    here as well.  By skipping the Engine creation
    we don't even need a DBAPI to be available.

    Calls to context.execute() here emit the given string to the
    script output.

    """
    url = config.get_main_option("sqlalchemy.url")
    context.configure(
        url=url,
        target_metadata=target_metadata,
        literal_binds=True,
        dialect_opts={"paramstyle": "named"},
    )

    with context.begin_transaction():
        context.run_migrations()


def run_migrations_online() -> None:
    """Run migrations in 'online' mode.

    In this scenario we need to create an Engine
    and associate a connection with the context.

    """
    connectable = engine_from_config(
        config.get_section(config.config_ini_section, {}),
        prefix="sqlalchemy.",
        poolclass=pool.NullPool,
    )

    with connectable.connect() as connection:
        context.configure(
            connection=connection, target_metadata=target_metadata
        )

        with context.begin_transaction():
            context.run_migrations()


if context.is_offline_mode():
    run_migrations_offline()
else:
    run_migrations_online()
```

上記コードで実施した変更点を、目的とあわせて以下に整理しました：

| 追加・修正内容                                                 | 理由・目的                                                                 |
|------------------------------------------------------------------|------------------------------------------------------------------------------|
| `import os`, `import sys` の追加                                | `.env` の読み込みやパス操作に必要                                          |
| `from dotenv import load_dotenv` の追加                         | `.env` を使用して接続情報を管理するため                                    |
| `load_dotenv()` の呼び出し                                      | `.env` を読み込むための処理                                                 |
| `os.getenv("DATABASE_URL")` を取得し `config.set_main_option(...)` に渡す | `.env` にある DB 接続情報を Alembic に反映させるため                       |
| `sys.path.append(...)` の追加                                   | Alembic が `app/` ディレクトリをインポートできるようにするため             |
| `from app.database import Base` の追加                          | Alembic に SQLAlchemy のメタデータを渡すため                               |
| `from app import models` の追加                                 | モデルを明示的に読み込んで `Base.metadata` に登録させるため                |
| `target_metadata = None` → `target_metadata = Base.metadata` に変更 | Alembic の `--autogenerate` を機能させるため                                |

## マイグレーションの実行と確認
### 1. マイグレーションファイルを作成する
マイグレーションファイルとは、テーブル作成・カラム追加・型変更など、データベース
構造の変更履歴を記録するファイルです。  
以下のコマンドで、作成します：

```bash
alembic revision --autogenerate -m "コメント(具体的な変更内容)"
```

今回は、todos テーブルを作成するためのマイグレーションファイルを生成します：

```bash
alembic revision --autogenerate -m "create todos table"
```

:::note warn
` -m ` オプションで指定するコメントはマイグレーションファイル名にも使われます。履歴の可読性を保つため、具体的に変更内容を記述する必要があります。（例："create todos table"、"add is_done column to todos" など）
:::

コマンドを実行すると、以下のようなログが表示されます：

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3958955/d0d0631d-6a03-4bb4-aac7-c41ee601cf67.png)

このログはマイグレーションファイルが正常に生成されたことを示しています。 
最後に `done` と表示されていれば処理は成功しています。

生成されたファイルは、次のパスに保存されます：
 `migrations/versions/xxxxxxxx_create_todos_table.py `

ここで `xxxxxxxx` は、Alembic によって自動生成されるバージョンID（タイムスタンプに基づく一意の識別子）です。このファイルは、テーブル構造の変更履歴としてバージョン管理され、チーム開発においても、**誰が・いつ・どのようなテーブル変更を行ったか**を履歴として残すことができ、一貫したスキーマ管理が可能になります。

### 2\. マイグレーションを適用する
マイグレーションファイルの生成だけでは、データベースに変更は適用されません。
次のコマンドを実行することで、マイグレーションの内容が データベースに反映されます：

```bash
alembic upgrade head
```

このコマンドは、versions/ ディレクトリ内の最新バージョン（head）までの変更を一括で適用します。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3958955/637dcfdc-d86b-4a30-8360-56931d3dc8bb.png)

todosテーブル

:::note info
#### Alembic の主なマイグレーション操作

##### マイグレーションを適用する（アップグレード）
- `alembic upgrade <バージョン>`：指定したバージョンに更新
- `alembic upgrade +1`：1つバージョンを進める
- `alembic upgrade head`：最新バージョンに進める（通常使用する操作）

##### マイグレーションを戻す（ダウングレード）
- `alembic downgrade <バージョン>`：指定したバージョンにロールバック
- `alembic downgrade -1`：1つ前のバージョンに戻す
- `alembic downgrade base`：すべてのマイグレーションを取り消し、初期状態に戻す
:::

## アプリケーションの起動
マイグレーションが完了したら、FastAPIアプリケーションを起動しましょう。
以下のコマンドで開発サーバーを起動します：

```bash
uvicorn app.main:app --reload
```

uvicorn <モジュールパス>:<FastAPIインスタンス名> --reload

- `app.main` ： Pythonモジュール（app/main.py）
- `:app`： その中で定義された FastAPI インスタンス app = FastAPI(...)

:::note tip
**--reload オプション** 
コード変更を検知して自動で再起動してくれる開発用の便利機能です。
本番環境では使わず、開発時のみ使用しましょう。
:::

起動後、ブラウザで以下のURLにアクセスしてください：
http://localhost:8000/

以下のようなJSONレスポンスが表示されれば、アプリの起動は成功です！
```json
{"message":"Welcome to Todo API"}
```

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3958955/c0456341-297b-4579-9983-5bf0cf6d8fc5.png)

## APIの動作確認（Swagger UI）
FastAPIには、APIドキュメント（Swagger UI）を自動生成する機能が備わっています。
アプリを起動した状態で、次のURLにアクセスしてみましょう：
http://localhost:8000/docs

ブラウザ上に、以下のようなSwagger UIが表示されます：

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3958955/86c097da-cf2a-4b66-af81-edd62d789bda.png)

この画面では、各エンドポイントの説明やリクエストパラメータ、レスポンスの形式などが確認できます。また、「Try it out」ボタンを使って実際にAPIを叩くことも可能です。

:::note tip 
**FastAPI における自動生成ドキュメントについて**
FastAPIは、OpenAPI 仕様に準拠した自動ドキュメント生成機能 を標準で備えています。
アプリケーションを起動すると、以下の2種類のドキュメントが自動で生成されます：

-  **Swagger UI（/docs）**
    - FastAPI 標準のインタラクティブなドキュメントUI
    - 「Try it out」機能があり、フォームに値を入力して実際にAPIを叩くことが可能
    - APIエンドポイントの動作確認やテストに便利
    
-  **ReDoc（/redoc）**
    - 左側にAPI一覧、右側に詳細が表示される閲覧専用のドキュメント
    - カテゴリごとの構造がわかりやすく、外部公開用のAPIリファレンスとして優秀

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3958955/c0df4fc7-77e2-49ce-9f9e-f5ecc4d66148.png)

:::

## まとめ
FastAPIは軽量かつ柔軟なAPI開発に特化したフレームワークです。しかし、Djangoのようなスキーマ管理機能は内蔵されていないため、Alembicによるマイグレーション環境の構築が必須となります。

https://fastapi.tiangolo.com/ja/tutorial/sql-databases/

https://zenn.dev/shimakaze_soft/articles/4c0784d9a87751

https://qiita.com/ktamido/items/8c3e56de1e889ec8a4cf

https://scrapbox.io/PythonOsaka/Alembic%E3%81%A7%E3%83%9E%E3%82%A4%E3%82%B0%E3%83%AC%E3%83%BC%E3%82%B7%E3%83%A7%E3%83%B3%E3%82%92%E3%81%97%E3%81%A6%E3%81%BF%E3%82%88%E3%81%86