【初心者OK】FastAPI×MySQLをDockerで連携!Python開発環境を最速構築する方法

【初心者OK】FastAPI×MySQLをDockerで連携!Python開発環境を最速構築する方法 Python
【初心者OK】FastAPI×MySQLをDockerで連携!Python開発環境を最速構築する方法
この記事は約28分で読めます。

未経験でも気軽に!サブスク型プログラミングスクール【Freeks】

困ってた自分に届けたい話

上司
上司

FastAPIで、フロントから送られた
名前・メールアドレス・パスワードをMySQLに登録しておいて

・・・いや、はじめてのPython開発でそれ言う!?
フォルダ構成?DB接続?何もわからん!

でも、調べまくって、なんとか FastAPI × MySQL × Docker の動く環境を構築できました。

てんハロ運営者
てんハロ運営者

この記事は、同じように困っていた方への備忘録兼シェアとして書いています。

使用した技術スタック

  • FastAPI(Python製の軽量Webフレームワーク)
  • MySQL(データベース)
  • Docker Compose(複数のコンテナをまとめて起動)
  • Next.js(フロントエンド/フォーム送信で使用)

プロジェクト構成

【初心者OK】FastAPI×MySQLをDockerで連携!Python開発環境を最速構築する方法

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>
  );
}
【初心者OK】FastAPI×MySQLをDockerで連携!Python開発環境を最速構築する方法

FastAPIのバックエンド側の実装

各ファイルの役割

ファイル内容
backend/db.pyDB接続の設定を記述
backend/main.pyFastAPIの本体とCORS、ルーティング設定
backend/models/user.pyusersテーブル定義(UUID、カラムなど)
backend/schemas/user.pyPydanticで受け取りバリデーション
backend/utils/common_fields.py登録時の共通フィールドを自動付与
backend/routers/registration.pyPOSTでデータ受取→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_byupdated_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 コンテナ名
てんハロ運営者
てんハロ運営者

おつかれさまでした!

更新をF5連打で待つの、そろそろやめませんか?
( ブログ更新をメールでそっとお知らせします🙇‍♂️ )

スパムはしません!詳細については、プライバシーポリシーをご覧ください。

コメント