Skip to content

フォルダ構成

FastAPIには、Railsのような厳格なフォルダ構成の規約はありませんが、大規模なアプリケーションを開発する際には、役割ごとにファイルを分けることが推奨されています。これにより、コードの可読性、保守性、そして再利用性が向上します。

一般的なフォルダ構成(APIモードの場合)

Section titled “一般的なフォルダ構成(APIモードの場合)”
.
├── app/
│ ├── __init__.py # Pythonパッケージとして認識させるための空ファイル
│ ├── main.py # アプリケーションのエントリーポイント
│ ├── api/ # APIエンドポイントを管理するディレクトリ
│ │ ├── __init__.py
│ │ ├── v1/ # APIのバージョン管理
│ │ │ ├── __init__.py
│ │ │ └── endpoints/ # 各エンドポイントの機能
│ │ │ ├── users.py
│ │ │ ├── items.py
│ │ │ └── ...
│ ├── core/ # アプリケーションのコア設定
│ │ ├── __init__.py
│ │ ├── config.py # 環境変数や設定ファイル
│ │ └── security.py # 認証・認可関連のロジック
│ ├── db/ # データベース関連のファイル
│ │ ├── __init__.py
│ │ ├── database.py # データベース接続情報
│ │ └── models.py # SQLAlchemyなどのORMモデル
│ ├── schemas/ # Pydanticモデル
│ │ ├── __init__.py
│ │ ├── user_schema.py
│ │ └── item_schema.py
│ └── crud/ # CRUD (作成, 読み取り, 更新, 削除) ロジック
│ ├── __init__.py
│ ├── user_crud.py
│ └── item_crud.py
├── tests/ # テストコード
├── .env # 環境変数
├── .gitignore
├── Dockerfile # Dockerコンテナの設定ファイル
└── requirements.txt # 依存関係
  • app/: アプリケーションのメインコードが格納されるルートディレクトリです。
  • app/main.py: アプリケーションのエントリーポイントです。ここでFastAPI()インスタンスを初期化し、ルーターをインクルードします。
  • app/api/: APIエンドポイントを定義する場所です。
  • app/api/v1/: APIのバージョンを管理するためのディレクトリです。これにより、将来のバージョンアップにも対応しやすくなります。
  • app/api/v1/endpoints/: 各エンドポイント(例:users.py、items.py)をファイルごとに分割することで、コードの整理と管理がしやすくなります。
  • app/core/: アプリケーション全体で共有される設定やユーティリティを格納します。
  • app/db/: データベース接続やORMモデルなど、データベース関連のロジックを管理します。
  • app/schemas/: Pydanticモデルを定義する場所です。これにより、リクエストやレスポンスのデータのバリデーションとシリアライズが明確になります。
  • app/crud/: データベースに対するCRUD操作(作成、読み取り、更新、削除)のロジックを分離します。これにより、ビジネスロジック(エンドポイント)からデータベース操作を切り離し、再利用性を高めます。

これらのフォルダ構成はあくまで推奨例であり、プロジェクトの規模や要件に応じて柔軟に調整することが重要です。この構造を採用することで、小規模なプロジェクトから大規模なサービスまで、一貫性のある開発が可能になります。

FastAPIの強力な機能を活用することで、より効率的で高品質なアプリケーションを構築できます。

1. ミドルウェア (Middleware) 🛡️

Section titled “1. ミドルウェア (Middleware) 🛡️”

ミドルウェアは、すべてのリクエストやレスポンスに共通の処理を適用するためのレイヤーです。これにより、各エンドポイントに同じコードを繰り返し書く必要がなくなります。

app/core/middleware.py
from fastapi.middleware.cors import CORSMiddleware
def add_cors_middleware(app):
"""
CORSミドルウェアをアプリケーションに追加
"""
app.add_middleware(
CORSMiddleware,
allow_origins=["*"], # 許可するオリジン (例: ["http://localhost:3000"])
allow_credentials=True, # クッキーや認証情報を許可するか
allow_methods=["*"], # 許可するHTTPメソッド (例: ["GET", "POST"])
allow_headers=["*"], # 許可するHTTPヘッダー
)
app/main.py
from fastapi import FastAPI
from app.core.middleware import add_cors_middleware
app = FastAPI()
# CORS ミドルウェアを追加
add_cors_middleware(app)
  • 利用例: アプリケーション全体の認証・認可、リクエスト/レスポンスのロギング、異なるオリジンからの通信を許可するCORS設定など。

2. 依存性注入 (Dependency Injection) 💉

Section titled “2. 依存性注入 (Dependency Injection) 💉”

FastAPIのDIシステムは、エンドポイント関数が必要とするオブジェクトやサービス(依存関係)を自動的に提供する仕組みです。

  • 利用例: リクエストごとに自動で開閉されるデータベースセッションの取得や、認証済みユーザー情報の取得など、共通のサービスをシンプルに利用できます。これにより、コードの再利用性が高まり、テストも容易になります。
app/db/database.py
from sqlalchemy import create_engine
from sqlalchemy.orm import sessionmaker
SQLALCHEMY_DATABASE_URL = "sqlite:///./test.db"
engine = create_engine(SQLALCHEMY_DATABASE_URL, connect_args={"check_same_thread": False})
SessionLocal = sessionmaker(autocommit=False, autoflush=False, bind=engine)
# データベースセッションを取得する関数
def get_db():
db = SessionLocal()
try:
yield db
finally:
db.close()
app/api/v1/endpoints/users.py
from fastapi import APIRouter, Depends, HTTPException
from sqlalchemy.orm import Session
from app.db.database import get_db
from app.schemas.user_schema import UserCreate, UserResponse
from app.crud.user_crud import create_user_crud
router = APIRouter()
@router.post("/users/", response_model=UserResponse)
def create_user(user: UserCreate, db: Session = Depends(get_db)):
db_user = create_user_crud(db, user)
if not db_user:
raise HTTPException(status_code=400, detail="User already exists")
return db_user

ポイント:

Depends(get_db) で自動的に DB セッションがビューに渡される

モック化してテストする際も簡単に差し替え可能

FastAPIは、Pythonのasync/await構文をネイティブにサポートしており、非同期処理を効率的に行えます。

  • メリット: 外部API呼び出しやDBアクセスといったI/O待ちが発生する処理を効率的に管理できます。これにより、サーバーが複数のリクエストを同時に処理できるようになり、パフォーマンスが大幅に向上します。
app/services/external_api.py
import httpx
async def fetch_data(url: str):
async with httpx.AsyncClient() as client:
response = await client.get(url)
return response.json()
app/api/v1/endpoints/items.py
from fastapi import APIRouter
from app.services.external_api import fetch_data
router = APIRouter()
@router.get("/items/")
async def get_items():
data = await fetch_data("https://api.example.com/items")
return {"items": data}

ポイント:

async def と await を使うことで、他のリクエストをブロックせずに処理可能

DBアクセスや外部API呼び出しの多いサービスで特に有効