0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

【FastAPI入門】オンメモリから脱却!Docker×PostgreSQL×SQLAlchemyでセキュアなデータ永続化を実装する(開発記録Day2)

0
Last updated at Posted at 2026-06-03

はじめに

こんにちは!サイバーセキュリティやゼロトラストアーキテクチャを学んでいる情報系の大学生です。
現在、7日間で「セキュア社内掲示板」をゼロから開発するプロジェクトに挑戦しています。

プロジェクト2日目である今回は、オンメモリで動かしていた初期のAPIから脱却し、データベースを導入して「データを安全かつ確実に永続化する仕組み」を構築しました。

この記事では、Dockerを使った隔離されたPostgreSQL環境の構築から、SQLAlchemy(ORM)を用いてFastAPIとセキュアに連携させるまでの手順を、わかりやすく解説します。

1. 全体像(アーキテクチャ)の理解

コードを書き始める前に、「誰が何の役割をしているのか」を整理しましょう。現実世界の「倉庫システム」に例えると非常にイメージしやすくなります。

  • PostgreSQL + Docker(隔離された安全な倉庫)
    データを実際に保存・管理する場所です。ホストOS(自分のPC)に直接データベースをインストールせず、Dockerを使って隔離されたコンテナ(専用の箱)の中で稼働させます。これにより、環境をクリーンに保ちつつセキュリティを高めることができます。
  • FastAPI + Pydantic(厳しい受付と検品所)
    外部からのリクエスト(投稿データなど)を受け取る最初の窓口です。Pydanticが「タイトルの文字数は適切か?」「必須項目は揃っているか?」を入り口で厳しくチェック(バリデーション)し、不正なデータはここで弾き返します。
  • SQLAlchemy(倉庫専用の優秀な通訳)
    Pythonのコードを、データベースが理解できる言語(SQL)に翻訳して命令を出してくれるORM(Object-Relational Mapping)です。生のSQLを直接書かないことで、SQLインジェクションなどの脆弱性を防ぐ重要な役割も担います。

2. DockerでPostgreSQL環境を構築

ローカル環境を汚さず、再現性の高いデータベース環境を作るために docker-compose.yml を作成します。

services:
  db:
    image: postgres:16-alpine
    container_name: secure-board-db
    restart: always
    env_file:
      - .env
    ports:
      - "5432:5432"
    volumes:
      - postgres_data:/var/lib/postgresql/data

volumes:
  postgres_data:

セキュリティ・設計のポイント

  • 軽量イメージの採用: alpine 版(軽量Linux)を採用することで、不要なパッケージを削ぎ落とし、攻撃対象領域(アタックサーフェス)を最小化しています。
  • 機密情報の分離: データベースのパスワード等は .env ファイルに切り出し、コードに直接書き込まない(ハードコードしない)セキュアな設計にしています。

3. SQLAlchemyを用いたDB接続とモデル定義

データベースとやり取りするための土台を作ります。

データベース接続設定 (database.py)

PythonからPostgreSQLへアクセスするためのセッション(通信の窓口)を作成します。

import os
from sqlalchemy import create_engine
from sqlalchemy.orm import sessionmaker, declarative_base
from dotenv import load_dotenv

load_dotenv()

# 環境変数から接続情報を取得
DB_USER = os.getenv("POSTGRES_USER", "secure_user")
DB_PASSWORD = os.getenv("POSTGRES_PASSWORD", "secure_password")
DB_NAME = os.getenv("POSTGRES_DB", "secure_board_db")

SQLALCHEMY_DATABASE_URL = f"postgresql://{DB_USER}:{DB_PASSWORD}@localhost:5432/{DB_NAME}"

# エンジンとセッションの作成
engine = create_engine(SQLALCHEMY_DATABASE_URL)
SessionLocal = sessionmaker(autocommit=False, autoflush=False, bind=engine)
Base = declarative_base()

テーブル構造の定義 (models.py)

SQLAlchemyを使って、実際のデータベースのテーブル構造をPythonのクラスとして定義します。

from sqlalchemy import Column, Integer, String
from database import Base

class Article(Base):
    __tablename__ = "articles"

    id = Column(Integer, primary_key=True, index=True)
    title = Column(String(255), nullable=False)
    content = Column(String, nullable=False)

4. FastAPIでCRUDエンドポイントを実装

いよいよ、API経由でデータベースにデータを読み書きする処理(Create, Read, Delete)を main.py に実装します。

from fastapi import FastAPI, Depends, HTTPException
from sqlalchemy.orm import Session
import models
from database import SessionLocal, engine
from pydantic import BaseModel

app = FastAPI()

# リクエストごとにDBセッションを安全に管理
def get_db():
    db = SessionLocal()
    try:
        yield db
    finally:
        db.close()

# --- Pydanticモデル(受付用スキーマ) ---
class ArticleCreate(BaseModel):
    title: str
    content: str

class Article(ArticleCreate):
    id: int
    model_config = {"from_attributes": True}

# --- エンドポイント ---
# 新規データの保存(Create)
@app.post("/articles", response_model=Article)
def create_article(article: ArticleCreate, db: Session = Depends(get_db)):
    # PydanticモデルからSQLAlchemyモデルへ安全に詰め替え
    db_article = models.Article(title=article.title, content=article.content)
    
    db.add(db_article)
    db.commit()          # ここで初めてDBに保存される
    db.refresh(db_article)
    return db_article

セキュリティ・設計のポイント

  • 安全なセッション管理: Dependsyield を使用することで、エラーが起きても確実にデータベース接続を閉じます。これによりコネクションプールの枯渇(DoS状態)を防ぎます。
  • PydanticとSQLAlchemyの分離: クライアントから受け取ったデータをそのままDBに突っ込むのではなく、Pydanticで型チェックを通った安全なデータのみを抽出してDBモデルに詰め替えています。これにより、意図しないデータの改ざん(Mass Assignmentなど)を防ぐことができます。

おわりに

今回はFastAPIとデータベースを繋ぎ、「データを安全に永続化する」というバックエンドの非常に重要な土台を構築しました。
「受付・検品(Pydantic) → 翻訳(SQLAlchemy) → 保管(PostgreSQL)」というデータのバケツリレーを意識することで、複雑なシステムもスッキリと理解できるようになります。

次回は、Webアプリケーションの要となる「セッション管理とセキュアな認証基盤(JWTやパスワードハッシュ化)」の実装に挑戦します!

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?