未経験でも気軽に!サブスク型プログラミングスクール【Freeks】
困ってた自分に届けたい話

FastAPIで、フロントから送られた
名前・メールアドレス・パスワードをMySQLに登録しておいて
・・・いや、はじめてのPython開発でそれ言う!?
フォルダ構成?DB接続?何もわからん!
でも、調べまくって、なんとか FastAPI × MySQL × Docker の動く環境を構築できました。

この記事は、同じように困っていた方への備忘録兼シェアとして書いています。
使用した技術スタック
- FastAPI(Python製の軽量Webフレームワーク)
- MySQL(データベース)
- Docker Compose(複数のコンテナをまとめて起動)
- Next.js(フロントエンド/フォーム送信で使用)
プロジェクト構成

FastAPI × Docker 開発環境のセットアップ
環境変数(.env.local)の設定方法
環境変数をルート直下に .env.local
として作成します。(開発環境で実行するため)
Dockerコンテナ間通信では DB_HOST
を MySQL サービス名にします。
DB_HOST=
DB_PORT=
DB_NAME=
DB_USER=
DB_PASSWORD=
Docker(MySQL × FastAPI 連携)の書き方
対象ファイル:docker/docker-compose.yml
MySQLとFastAPIを同時に立ち上げるDocker Compose設定です。
すでにMySQLの設定がある場合は、FastAPIの定義だけ追加してください。
version: '3'
services:
mysql:
image: mysql:8.0
... # 詳細は別記事へ
FastAPI:
build:
context: .. // Dockerfile がある位置を指定
dockerfile: docker/Dockerfile
container_name: 任意のコンテナ名
ports:
- "8000:8000"
volumes:
- ../backend:/app
env_file:
- ../.env.local
depends_on: // 「このアプリは mysql が先に起動していないとダメだよ」という意味
- mysql
MySQLの設定方法は下記の記事をチェックしてください。
FastAPIアプリ起動設定
対象ファイル:docker/ Dockerfile
FastAPIアプリの起動手順を定義する Dockerfile を用意します。
⚠️ 注意点
- 大文字スタートの
Dockerfile
というファイル名でなければいけない - 拡張子は 不要・つけてはいけない(
.txt
や.py
などはNG)
// Pythonの軽くて早いバージョンを指定
FROM python:3.10-slim
// 実行時に.pycファイルを作らないように設定(大量にできてGitに上げれなくなる)
ENV PYTHONDONTWRITEBYTECODE=1
// コンテナ内で作業するディレクトリを作成
WORKDIR /app
// ホスト側の ./backend フォルダを、コンテナ内の /app に丸ごとコピー
COPY ./backend /app
// requirements.txt をコピーして、必要なライブラリをインストール
COPY ./backend/requirements.txt .
RUN pip install --upgrade pip
RUN pip install -r requirements.txt
// アプリを起動
CMD ["uvicorn", "main:app", "--host", "0.0.0.0", "--port", "8000", "--reload"]
requirements.txt の作成とバージョン管理
対象ファイル:backend/requirements.txt
Pythonパッケージのインストール一覧を記述します。
下記のコマンドで、Dockerで一括で自動インストールすることができます。
pip install -r requirements.txt
🌱 豆知識
パッケージ名しか書いていない場合:常に最新バージョンがインストールされる(試作段階・練習中向け)
fastapi
uvicorn
SQLAlchemy
PyMySQL
python-dotenv
バージョンを指定している場合:誰が使っても同じ環境になる(チーム開発・本番運用向け)
fastapi==0.116.0
uvicorn==0.35.0
SQLAlchemy==2.0.41
PyMySQL==1.1.1
python-dotenv==1.1.1
.gitignore の設定でGitをクリーンに保つ
対象ファイル:.gitignore
Pythonのをインストールすると自動生成ファイルができて、Gitにそのまま上げると大変なことになります。
下記のように設定すると、Gitに不要なファイルが混ざらなくなります。おすすめです。
# バーチャル環境除外
venv/
# Pythonのバイトコードキャッシュを無視
__pycache__/
*.pyc
*.pyo
*.pyd
テーブル作成
事前に users
テーブルを作っておきましょう。DockerのMySQL内で作成できます。
作成方法については、下記の記事をご覧ください。
Next.jsで登録フォームを作成
下記は登録フォームの registerForm.tsx
の内容の内容です。register/page.tsx
で呼び出すと、下記の画像のような登録フォームになります。
"use client";
import { useState } from "react";
export default function RegisterForm() {
const [form, setForm] = useState({
name: "",
email: "",
password: "",
});
const [message, setMessage] = useState("");
const handleChange = (e: React.ChangeEvent<HTMLInputElement>) => {
setForm({ ...form, [e.target.name]: e.target.value });
};
const handleSubmit = async (e: React.FormEvent) => {
e.preventDefault();
try {
const res = await fetch("http://localhost:8000/registration", {
method: "POST",
headers: {
"Content-Type": "application/json",
},
body: JSON.stringify(form),
});
const data = await res.json();
if (res.ok) {
setMessage("登録成功! ユーザーID: " + data.user_id);
} else {
setMessage("登録失敗: " + (data.detail || "エラーが発生しました"));
}
} catch (error) {
console.error("エラー:", error);
setMessage("通信エラーが発生しました");
}
};
return (
<form onSubmit={handleSubmit} className="space-y-4 max-w-md mx-auto mt-10">
<div>
<label htmlFor="name" className="block font-medium mb-1">
お名前
</label>
<input
id="name"
name="name"
placeholder="例:山田 太郎"
value={form.name}
onChange={handleChange}
required
className="border px-3 py-2 w-full"
/>
</div>
<div>
<label htmlFor="email" className="block font-medium mb-1">
メールアドレス
</label>
<input
id="email"
name="email"
placeholder="例:taro@example.com"
type="email"
value={form.email}
onChange={handleChange}
required
className="border px-3 py-2 w-full"
/>
</div>
<div>
<label htmlFor="password" className="block font-medium mb-1">
パスワード
</label>
<input
id="password"
name="password"
placeholder="半角英数字8文字以上"
type="password"
value={form.password}
onChange={handleChange}
required
className="border px-3 py-2 w-full"
/>
</div>
<button
type="submit"
className="bg-blue-600 text-white px-4 py-2 rounded w-full"
>
ユーザー登録
</button>
{message && <p className="mt-4 text-sm text-gray-700">{message}</p>}
</form>
);
}

FastAPIのバックエンド側の実装
各ファイルの役割
ファイル | 内容 |
---|---|
backend/db.py | DB接続の設定を記述 |
backend/main.py | FastAPIの本体とCORS、ルーティング設定 |
backend/models/user.py | usersテーブル定義(UUID、カラムなど) |
backend/schemas/user.py | Pydanticで受け取りバリデーション |
backend/utils/common_fields.py | 登録時の共通フィールドを自動付与 |
backend/routers/registration.py | POSTでデータ受取→DB保存処理 |
db.py:DB接続設定
.env.local
を読み込んで DB に接続する準備をする
from sqlalchemy import create_engine // DBとの接続エンジンを作るための関数
from sqlalchemy.orm import sessionmaker, declarative_base
from dotenv import load_dotenv // .envファイルから環境変数を読み込むための関数
import os // 環境変数を取得するための標準ライブラリ
// ルートの.env読み込み
load_dotenv(dotenv_path=".env.local")
DB_HOST = os.getenv("DB_HOST")
DB_PORT = os.getenv("DB_PORT")
DB_NAME = os.getenv("DB_NAME")
DB_USER = os.getenv("DB_USER")
DB_PASSWORD = os.getenv("DB_PASSWORD")
// データベース接続用のURLを作成
DB_URL = f"mysql+pymysql://{DB_USER}:{DB_PASSWORD}@{DB_HOST}:{DB_PORT}/{DB_NAME}?charset=utf8mb4"
// 接続準備
engine = create_engine(DB_URL)
SessionLocal = sessionmaker(bind=engine, autocommit=False, autoflush=False)
Base = declarative_base()
main.py:アプリ起動とCORS設定
FastAPIアプリを起動し、CORS設定とルーター登録を行います。
Next.js開発環境で実行しているので、今回はhttp://localhost:3000
を指定(ここは環境変数設定にしたほうがいいかもです)
from fastapi import FastAPI
from fastapi.middleware.cors import CORSMiddleware // 別ドメインからのアクセスを許可するための設定
from routers import registration
// FastAPIアプリケーションの本体を作成
app = FastAPI()
// CORS(クロスオリジン)設定を追加:別のドメインからアクセスを許可する
app.add_middleware(
CORSMiddleware,
allow_origins=["http://localhost:3000"], // フロントエンド(Next.js)からのアクセスを許可
allow_credentials=True, // クッキーなどの認証情報を含めた通信を許可
allow_methods=["*"], // GETやPOSTなど、すべてのHTTPメソッドを許可
allow_headers=["*"], // すべてのリクエストヘッダーを許可(認証トークンなど)
)
// APIの処理を追加(今回はregistration.pyのルーター)
app.include_router(registration.router)
models/user.py:ユーザーテーブル定義
SQLAlchemyで userテーブル
構造を定義します。主キーは UUID
を自動生成。
import uuid
from sqlalchemy import Column, String, Boolean, DateTime
from db import Base
class Users(Base):
__tablename__ = "users"
user_id = Column(String(36), primary_key=True, default=lambda: str(uuid.uuid4()))
name = Column(String(100), nullable=False)
email = Column(String(100), nullable=False, unique=True)
password = Column(String(255), nullable=False)
updated_by = Column(String(100))
updated_at = Column(DateTime)
uuidについて、もっと知りたい方は下記の記事をどうぞ!
schemas/user.py:バリデーション用スキーマ定義
フロントから送られてくる入力値(name, email, password)をバリデーションします。
from pydantic import BaseModel
class UserCreate(BaseModel):
name: str
email: str
password: str
utils/common_fields.py:共通項目の自動付与
updated_by
や updated_at
などの共通項目を自動で付与します。
from datetime import datetime, timezone, timedelta
def generate_common_fields():
jst_now = datetime.now(timezone(timedelta(hours=9)))
return {
"updated_by": "system",
"updated_at": jst_now,
}
routers/registration.py:登録処理ルーターの作成
POSTされた情報をDBに保存するルーターです。辞書展開でスキーマ+共通フィールドを結合します。
from fastapi import APIRouter, Depends
from sqlalchemy.orm import Session // DBとのやりとりの型(Session)を指定
from db import SessionLocal
from models.user import Users
from schemas.user import UserCreate
from utils.common_fields import generate_common_fields
router = APIRouter()
// データベースとの接続を一時的に確立して、使い終わったら自動で切るための仕組み
def get_db():
db = SessionLocal() // DB接続を開始
try:
yield db // データを登録・検索
finally:
db.close() // DB接続を終了
@router.post("/registration")
def create_user(user: UserCreate, db: Session = Depends(get_db)):
common_fields = generate_common_fields()
db_user = Users(
**user.dict(),
**common_fields
)
db.add(db_user)
db.commit()
return {"message": "登録成功"}
※ここで辞書化の記事をつくっていれよう!
トラブル対応:ログでFastAPIのエラーを確認する方法
ログをリアルタイムで監視するには、以下のコマンドを使いましょう。
-f
は --follow
の略で「ログを継続して追いかける」オプションです。
docker logs -f コンテナ名

おつかれさまでした!
コメント