PythonのDockerでFastAPIを構築します
コンテナであるECRとして使用可能。
構成
Python
Docker
FastAPI
Windows
実装
main.py
>
from fastapi import FastAPI
from typing import Optional
from pydantic import BaseModel
app = FastAPI()
# POST用:リクエストボディの構造を定義
class Item(BaseModel):
name: str
price: float
description: Optional[str] = None
# 1. GETメソッド:クエリパラメータ 'q' を任意に設定
@app.get("/Gitems/")
def read_items(limit: int = 10, q: Optional[str] = None):
# qが渡されない場合は None になります
return {"limit": limit, "query": q, "message": "こちらはGETリクエストです"}
# 2. POSTメソッド:リクエストボディを受け取る
@app.post("/Pitems/")
def create_item(item: Item):
# 受け取ったデータをそのまま返す例
return {"item": item, "message": "アイテムを登録しました"}
Dockerfile
# 軽量なPythonイメージを使用
FROM python:3.11-slim
# 作業ディレクトリの設定
WORKDIR /app
# 依存関係ファイルのコピーとインストール
COPY requirements.txt .
RUN pip install --no-cache-dir -r requirements.txt
# ソースコードのコピー
COPY . .
# FastAPI(Uvicorn)を起動
# --host 0.0.0.0 はコンテナ外からのアクセスを許可するために必須です
CMD ["uvicorn", "main:app", "--host", "0.0.0.0", "--port", "8000"]
requirements.txt
fastapi
uvicorn[standard]
pydantic
docker-compose.yml
services:
api:
build: .
ports:
- "8000:8000"
volumes:
- .:/app
environment:
- PYTHONUNBUFFERED=1
実行
dockerfileがある場所に遷移して下記コマンドをたたく。 ※Dokcerのツールが必要DockerDesktopがいい。
docker compose up --build
docker compose up -d
URLで下記をたたくだけ
http://localhost:8000/docs
FastAPI のテストまとめ
FastAPIアプリケーションのテスト方法について整理します。
1. 基本方針
- pytest を使用する
- TestClient でAPIを疑似的に呼び出す
- 外部依存(DBなど)はモック or テスト用に分離
2. TestClient を使った基本テスト
サンプルコード
from fastapi import FastAPI
from fastapi.testclient import TestClient
app = FastAPI()
@app.get("/hello")
def hello():
return {"message": "Hello World"}
client = TestClient(app)
def test_hello():
response = client.get("/hello")
assert response.status_code == 200
assert response.json() == {"message": "Hello World"}
3. pytest の実行
pytest
オプション例:
pytest -v # 詳細表示
pytest -q # 簡易表示
pytest --maxfail=1
4. 非同期エンドポイントのテスト
FastAPIは async/await に対応しているため、非同期テストも可能。
import pytest
from httpx import AsyncClient
@pytest.mark.asyncio
async def test_async():
async with AsyncClient(app=app, base_url="http://test") as ac:
response = await ac.get("/hello")
assert response.status_code == 200
5. 依存関係(Depends)のモック
FastAPIの依存関係は override で差し替え可能。
from fastapi import Depends
def get_db():
return "real_db"
def override_db():
return "test_db"
app.dependency_overrides[get_db] = override_db
6. データベーステスト
パターン1:テスト用DB
- SQLite(インメモリ)を使用
- テストごとに初期化
SQLALCHEMY_DATABASE_URL = "sqlite:///./test.db"
パターン2:トランザクションロールバック
- テスト終了後にロールバック
- 実DBに近い動作確認が可能
7. 認証付きAPIのテスト
def test_auth():
headers = {"Authorization": "Bearer testtoken"}
response = client.get("/secure", headers=headers)
assert response.status_code == 200
8. テスト構成例
project/
├── app/
│ ├── main.py
│ └── api/
├── tests/
│ ├── test_api.py
│ └── conftest.py
9. conftest.py の活用
共通処理をfixtureとして定義。
import pytest
from fastapi.testclient import TestClient
@pytest.fixture
def client():
return TestClient(app)
10. カバレッジ計測
pytest --cov=app
HTML出力:
pytest --cov=app --cov-report=html
11. よくある落とし穴
- DB接続をモックしていない → テストが遅い
- dependency_overrides を戻し忘れる
- 非同期と同期の混在ミス
- グローバル状態の共有によるテスト干渉
- requestでdockerのコンテナのアプリを実行して試験しようとするが、リクエストがdocker composeでも通らない。
- 基本的にdockerにいれてコンテナで動作させるとAPIとなる。pythonソースだけであればAPIとして成り立たない。実行役が必要。Lambdaの場合は、別途(from mangum import Mangum)
12. CI/CDとの連携
- GitHub Actionsで自動実行
- push / pull request時にpytest実行
例:
- name: Run tests
run: pytest
まとめ
- TestClientで簡単にAPIテスト可能
- Dependsのoverrideが強力
- DBは分離 or モックが基本
- 非同期テストはAsyncClientを使う
- CI連携で品質担保
- ラムダに乗せたい場合は、既存がfastapiであり、最速で楽に移行したい場合に有効。しかし、ラムダの場合解釈のロジックを踏むのでノーマルなPythonと比べると遅くなる。
