はじめに
FastAPI と DynamoDB Local を組み合わせたローカル開発環境を構築し、JWT 認証付きの API 経由で DynamoDB Local にアクセスする構成を検証しました。この記事では、構築手順・疎通確認・実際に発生したエラーと対応策をまとめています。
本番環境では AWS 上の DynamoDB を使用することを前提としつつ、ローカル完結での開発・検証環境として DynamoDB Local を使用しています。
目的は以下の通りです:
- Docker Compose による FastAPI サーバーと DynamoDB Local の同時起動
- JWT 認証付きエンドポイントからの DynamoDB 操作確認(CRUD)
- 各種エンドポイントでのトークンベース認証によるアクセス検証
- DynamoDB Local との実際のデータ操作(PutItem / GetItem 相当)が行えることの確認
- 実際に遭遇したエラーとその原因・対処方法の記録
開発環境構成
項目 | 内容 |
---|---|
フレームワーク | FastAPI |
データベース | DynamoDB Local |
認証 | JWT(パスワード認証+トークン発行) |
SDK | boto3(AWS SDK for Python) |
実行環境 | Docker + docker-compose による構築 |
DynamoDB Local とは?
DynamoDB Local は、AWS の NoSQL データベースである DynamoDB を、ローカル環境で擬似的に動作させるためのソフトウェア(開発用エミュレーター)です。つまり、「DynamoDBにリクエストを送るコードが正しく動くのか」をローカルで検証するための疑似環境です。Docker イメージとして提供されており、AWS アカウントや課金なしで DynamoDB と同様のインターフェースをローカルで再現することができます。
特徴
- AWS アカウントやインターネット接続なしで動作可能
-
boto3
やaws-sdk
から本番と同様に操作可能 -
-inMemory
オプションにより、データをファイルに保存せずメモリ上でのみ軽量に実行可能 - ユニットテストやローカル開発に適している
DynamoDB との違い
DynamoDB Local はあくまで「開発・検証専用の代替手段」であり、性能については本番環境と異なります。ただし、APIの仕様・リクエスト形式・データ構造は本番と同じであるため、ローカル開発・テスト環境としては実用的です。
DynamoDB | DynamoDB Local | |
---|---|---|
実行環境 | AWS リージョン上 | ローカルマシン or Docker コンテナ |
利用目的 | 本番運用、大規模・高可用アプリケーション | 開発・ユニットテスト・CI 実行用 |
課金 | 従量課金制 | 無料 |
認証 | IAM 認証が必要 | 認証不要(または任意) |
保存方式 | 永続保存(AWS リージョン内に保持) | ディスク保存 or メモリオンリー(-inMemory ) |
スケーラビリティ | 自動スケーリングに対応 | 単一ノードでスケーリング不可 |
SDK 互換性 | boto3 / aws-sdk など公式 SDK に対応 | 本番同様に SDK・API がそのまま使える |
実施内容と検証結果
Docker Compose による構成
以下は、FastAPI コンテナと DynamoDB Local コンテナを同時に立ち上げる構成です。
services:
web:
build: .
container_name: fastapi-app
ports:
- "8000:8000"
env_file:
- .env
depends_on:
- dynamodb
command: uvicorn main:app --host 0.0.0.0 --port 8000 --reload
environment:
- PYTHONPATH=/app
volumes:
- ./app:/app
dynamodb:
image: amazon/dynamodb-local
container_name: dynamodb-local
ports:
- "8001:8000"
volumes:
- dynamodb-data:/home/dynamodb
restart: always
volumes:
dynamodb-data:
実際に発生したエラーと解決策
ローカルで FastAPI サーバーから DynamoDB Local に接続しようとした際に 実際に遭遇したエラーと対応した内容です。
1. EndpointConnectionError: Could not connect to the endpoint URL
発生タイミング:
- FastAPI の起動直後、boto3 経由で DynamoDB Local へ接続した際に発生
エラーログ:
botocore.exceptions.EndpointConnectionError: Could not connect to the endpoint URL: "http://localhost:8000"
原因:
- FastAPI コンテナ内部から、localhost:8000 を参照していたが、これはFastAPI 自身のローカルホストを指しており、DynamoDB Local には到達しない
修正前:
endpoint_url = "http://localhost:8000"
修正後:
# Docker Compose の service 名で名前解決されるため、service名を使用
endpoint_url = "http://dynamodb:8000"
2. ResourceNotFoundException: Requested resource not found
発生タイミング:
- Admins や PostsなどDynamoDB Local にまだ存在しないテーブルに対して、
get_item()
やscan()
などを呼び出した場合に発生
エラーログ:
botocore.errorfactory.ResourceNotFoundException: An error occurred (ResourceNotFoundException) when calling the GetItem operation: Requested resource not found
原因:
- DynamoDB Local に対象テーブルが存在しない状態で boto3 を通じて操作しようとしたため
- 具体的には、
dynamodb.Table(...).get_item()
などを直接呼び出しているが、その前にテーブル作成create_table()
や存在確認load()
処理を行っていない
修正前:
import boto3
import os
dynamodb = boto3.resource(
"dynamodb",
region_name=os.environ["AWS_REGION"],
endpoint_url=os.environ["DYNAMODB_ENDPOINT"],
aws_access_key_id="dummy",
aws_secret_access_key="dummy"
)
# 存在チェック・作成なしで直接テーブル操作(エラーの原因)
settings_table = dynamodb.Table("SettingsTable")
response = settings_table.get_item(Key={"id": "app_settings"})
item = response.get("Item", {})
修正後:
# 以下のコードにより、実行時に SettingsTable が存在しない場合は作成されるように対応
def create_table_if_not_exists(table_name, key_schema, attribute_definitions, billing_mode="PAY_PER_REQUEST"):
try:
existing_tables = dynamodb_client.list_tables()["TableNames"]
if table_name in existing_tables:
print(f"既にテーブルが存在します: {table_name}")
return
dynamodb_client.create_table(
TableName=table_name,
KeySchema=key_schema,
AttributeDefinitions=attribute_definitions,
BillingMode=billing_mode # ← ここは明示的に関数引数から渡されている
)
print(f"テーブルを作成しました: {table_name}")
except ClientError as e:
print(f"DynamoDB操作中にエラーが発生しました: {e.response['Error']['Message']}")
raise
3. NoCredentialsError: Unable to locate credentials
発生タイミング:
- FastAPI起動時、bot3経由でDynamoDB Localアクセスした時に発生
エラーログ:
botocore.exceptions.NoCredentialsError: Unable to locate credentials
原因:
- DynamoDB Local は認証不要だが、boto3 は明示的に認証情報を渡さないと
~/.aws/credentials
を参照しようとして失敗する
修正前:
dynamodb = boto3.resource("dynamodb", endpoint_url="http://dynamodb:8000")
修正後:
# ダミーの認証情報を明示的に指定することで、解決
dynamodb = boto3.resource(
"dynamodb",
endpoint_url="http://dynamodb:8000",
region_name="ap-northeast-1",
aws_access_key_id="dummy",
aws_secret_access_key="dummy"
)
4. Unexpected error: Cannot connect to host dynamodb:8000 ssl:default
発生タイミング:
- Docker Compose 起動直後、FastAPI が DynamoDB より早く起動してboto3 によるアクセスが行われた場合に発生
エラーログ:
botocore.exceptions.EndpointConnectionError: Could not connect to the endpoint URL: "http://dynamodb:8000"
原因:
- Docker Compose の
depends_on
はコンテナのプロセス起動のみを保証し、アプリケーションが "ready" になることまでは保証しない - DynamoDB Local が "listen" 状態になる前に FastAPI 側がリクエストを出してしまった
対応:
- この問題は現在、
utils/dynamodb.py
を使用した手動テーブル作成スクリプトで 事前にテーブルが存在する状態を作る ことで回避した - リトライロジックを入れて待機させる実装は行っていない
検証で得られた知見
- DynamoDB Local でも boto3 は明示的な認証情報を要求する
- 本来 DynamoDB Local では IAM 認証は不要だが、boto3 はデフォルトで
~/.aws/credentials
を参照してしまうため、明示的にダミーのアクセスキーを渡す必要がある - これは boto3 の仕様上避けられないため、ローカル環境であっても
aws_access_key_id
/aws_secret_access_key
の指定が必須
- 本来 DynamoDB Local では IAM 認証は不要だが、boto3 はデフォルトで
- Docker Compose の depends_on は「起動順」だけで「起動完了待ち」にはならない
-
depends_on
によって FastAPI より先に DynamoDB Local コンテナは起動するが、DynamoDB 内部のリスナーが listen 状態になるまで待たない - そのため、FastAPI 側が即座に boto3 でアクセスを試みると
EndpointConnectionError
が発生する - 根本的な対応には、リトライ処理の追加または 起動前の明示的なテーブル初期化処理が必要
-
まとめ
FastAPI と DynamoDB Local を組み合わせて、ローカル開発環境を構築し、接続・疎通確認を行いました。この環境は、AWSリソースを使わず、CI/CDやユニットテストの前段階で信頼性のある開発を進めるためのベースとして非常に有用です。